From 713dcd8762c8f453dea7db70e628af10d4bd7e08 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 3 Aug 2019 22:27:48 -0700 Subject: [PATCH 001/199] Expand Memberwise Initializer Refactoring Action - Struct declarations are now eligible for the refactoring action - Default argument expressions specified in source are printed into the generated initializer as well Note that we are explicitly missing the ability to print a 'nil' default argument for members of type T? because TypeReprs are not fully resolved by the time the refactoring engine runs. --- lib/IDE/Refactoring.cpp | 144 +++++++++++++++++++++++----------------- 1 file changed, 83 insertions(+), 61 deletions(-) diff --git a/lib/IDE/Refactoring.cpp b/lib/IDE/Refactoring.cpp index 1cbdabf559006..bc1f5052ef276 100644 --- a/lib/IDE/Refactoring.cpp +++ b/lib/IDE/Refactoring.cpp @@ -2752,78 +2752,107 @@ bool RefactoringActionLocalizeString::performChange() { return false; } +struct MemberwiseParameter { + Identifier Name; + Type MemberType; + Expr *DefaultExpr; + + MemberwiseParameter(Identifier name, Type type, Expr *initialExpr) + : Name(name), MemberType(type), DefaultExpr(initialExpr) {} +}; + static void generateMemberwiseInit(SourceEditConsumer &EditConsumer, - SourceManager &SM, - SmallVectorImpl& memberNameVector, - SmallVectorImpl& memberTypeVector, - SourceLoc targetLocation) { - - assert(!memberTypeVector.empty()); - assert(memberTypeVector.size() == memberNameVector.size()); + SourceManager &SM, + ArrayRef memberVector, + SourceLoc targetLocation) { + assert(!memberVector.empty()); + EditConsumer.accept(SM, targetLocation, "\ninternal init("); - - for (size_t i = 0, n = memberTypeVector.size(); i < n ; i++) { - EditConsumer.accept(SM, targetLocation, memberNameVector[i] + ": " + - memberTypeVector[i]); - - if (i != memberTypeVector.size() - 1) { - EditConsumer.accept(SM, targetLocation, ", "); + auto insertMember = [&SM](const MemberwiseParameter &memberData, + llvm::raw_ostream &OS, bool wantsSeparator) { + OS << memberData.Name << ": " << memberData.MemberType.getString(); + if (auto *expr = memberData.DefaultExpr) { + if (isa(expr)) { + OS << " = nil"; + } else if (expr->getSourceRange().isValid()) { + auto range = + Lexer::getCharSourceRangeFromSourceRange( + SM, expr->getSourceRange()); + OS << " = " << SM.extractText(range); + } + } + + if (wantsSeparator) { + OS << ", "; } + }; + + // Process the initial list of members, inserting commas as appropriate. + std::string Buffer; + llvm::raw_string_ostream OS(Buffer); + for (const auto &memberData : memberVector.drop_back()) { + insertMember(memberData, OS, /*wantsSeparator*/ true); } - - EditConsumer.accept(SM, targetLocation, ") {\n"); - - for (auto varName: memberNameVector) { - EditConsumer.accept(SM, targetLocation, - "self." + varName + " = " + varName + "\n"); + + // Process the last (or perhaps, only) member. + insertMember(memberVector.back(), OS, /*wantsSeparator*/ false); + + // Synthesize the body. + OS << ") {\n"; + for (auto &member : memberVector) { + // self. = + OS << "self." << member.Name << " = " << member.Name << "\n"; } - - EditConsumer.accept(SM, targetLocation, "}\n"); + OS << "}\n"; + + // Accept the entire edit. + EditConsumer.accept(SM, targetLocation, OS.str()); } - -static SourceLoc collectMembersForInit(ResolvedCursorInfo CursorInfo, - SmallVectorImpl& memberNameVector, - SmallVectorImpl& memberTypeVector) { - + +static SourceLoc +collectMembersForInit(ResolvedCursorInfo CursorInfo, + SmallVectorImpl &memberVector) { + if (!CursorInfo.ValueD) return SourceLoc(); - ClassDecl *classDecl = dyn_cast(CursorInfo.ValueD); - if (!classDecl || classDecl->getStoredProperties().empty() || + NominalTypeDecl *nominalDecl = dyn_cast(CursorInfo.ValueD); + if (!nominalDecl || nominalDecl->getStoredProperties().empty() || CursorInfo.IsRef) { return SourceLoc(); } - - SourceLoc bracesStart = classDecl->getBraces().Start; + + SourceLoc bracesStart = nominalDecl->getBraces().Start; if (!bracesStart.isValid()) return SourceLoc(); SourceLoc targetLocation = bracesStart.getAdvancedLoc(1); if (!targetLocation.isValid()) return SourceLoc(); - - for (auto varDecl : classDecl->getStoredProperties()) { - auto parentPatternBinding = varDecl->getParentPatternBinding(); - if (!parentPatternBinding) + + for (auto varDecl : nominalDecl->getStoredProperties()) { + auto patternBinding = varDecl->getParentPatternBinding(); + if (!patternBinding) + continue; + + if (!varDecl->isMemberwiseInitialized(/*preferDeclaredProperties=*/true)) { continue; - - auto varDeclIndex = - parentPatternBinding->getPatternEntryIndexForVarDecl(varDecl); - - if (auto init = varDecl->getParentPatternBinding()->getInit(varDeclIndex)) { - if (init->getStartLoc().isValid()) - continue; } - - StringRef memberName = varDecl->getName().str(); - memberNameVector.push_back(memberName.str()); - - std::string memberType = varDecl->getType().getString(); - memberTypeVector.push_back(memberType); + + auto &entry = patternBinding->getPatternEntryForVarDecl(varDecl); + bool isExplicitlyInitialized = + entry.isInitialized() && entry.getEqualLoc().isValid(); + Expr *defaultInit = nullptr; + if (isExplicitlyInitialized || patternBinding->isDefaultInitializable()) { + defaultInit = varDecl->getParentInitializer(); + } + + memberVector.emplace_back(varDecl->getName(), + varDecl->getType(), defaultInit); } - if (memberNameVector.empty() || memberTypeVector.empty()) { + if (memberVector.empty()) { return SourceLoc(); } @@ -2833,25 +2862,18 @@ static SourceLoc collectMembersForInit(ResolvedCursorInfo CursorInfo, bool RefactoringActionMemberwiseInitLocalRefactoring:: isApplicable(ResolvedCursorInfo Tok, DiagnosticEngine &Diag) { - SmallVector memberNameVector; - SmallVector memberTypeVector; - - return collectMembersForInit(Tok, memberNameVector, - memberTypeVector).isValid(); + SmallVector memberVector; + return collectMembersForInit(Tok, memberVector).isValid(); } bool RefactoringActionMemberwiseInitLocalRefactoring::performChange() { - SmallVector memberNameVector; - SmallVector memberTypeVector; - - SourceLoc targetLocation = collectMembersForInit(CursorInfo, memberNameVector, - memberTypeVector); + SmallVector memberVector; + SourceLoc targetLocation = collectMembersForInit(CursorInfo, memberVector); if (targetLocation.isInvalid()) return true; - generateMemberwiseInit(EditConsumer, SM, memberNameVector, - memberTypeVector, targetLocation); + generateMemberwiseInit(EditConsumer, SM, memberVector, targetLocation); return false; } From 546734aea8bb363aa562721db92849a35aee14b6 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 3 Aug 2019 22:28:00 -0700 Subject: [PATCH 002/199] Move and expand the memberwise initializer test --- .../class_members.swift.expected | 14 ------- .../class_members.swift.expected | 40 ++++++++++++++++++ .../struct_members.swift.expected | 41 +++++++++++++++++++ .../MemberwiseInit/class_members.swift | 11 ----- .../MemberwiseInit/generate_memberwise.swift | 38 +++++++++++++++++ 5 files changed, 119 insertions(+), 25 deletions(-) delete mode 100644 test/refactoring/MemberwiseInit/Outputs/class_members/class_members.swift.expected create mode 100644 test/refactoring/MemberwiseInit/Outputs/generate_memberwise/class_members.swift.expected create mode 100644 test/refactoring/MemberwiseInit/Outputs/generate_memberwise/struct_members.swift.expected delete mode 100644 test/refactoring/MemberwiseInit/class_members.swift create mode 100644 test/refactoring/MemberwiseInit/generate_memberwise.swift diff --git a/test/refactoring/MemberwiseInit/Outputs/class_members/class_members.swift.expected b/test/refactoring/MemberwiseInit/Outputs/class_members/class_members.swift.expected deleted file mode 100644 index 5c3de898efb13..0000000000000 --- a/test/refactoring/MemberwiseInit/Outputs/class_members/class_members.swift.expected +++ /dev/null @@ -1,14 +0,0 @@ -class Person { -internal init(firstName: String?, lastName: String?, age: Int?) { -self.firstName = firstName -self.lastName = lastName -self.age = age -} - - var firstName: String! - var lastName: String! - var age: Int! - var planet = "Earth", solarSystem = "Milky Way" - var avgHeight = 175 -} - diff --git a/test/refactoring/MemberwiseInit/Outputs/generate_memberwise/class_members.swift.expected b/test/refactoring/MemberwiseInit/Outputs/generate_memberwise/class_members.swift.expected new file mode 100644 index 0000000000000..8745fd7235738 --- /dev/null +++ b/test/refactoring/MemberwiseInit/Outputs/generate_memberwise/class_members.swift.expected @@ -0,0 +1,40 @@ +class Person { +internal init(firstName: String? = nil, lastName: String? = nil, age: Int? = nil, planet: String = "Earth", solarSystem: String = "Milky Way", avgHeight: Int = 175) { +self.firstName = firstName +self.lastName = lastName +self.age = age +self.planet = planet +self.solarSystem = solarSystem +self.avgHeight = avgHeight +} + + var firstName: String! + var lastName: String! + var age: Int! + var planet = "Earth", solarSystem = "Milky Way" + var avgHeight = 175 + let line = #line, file = #file, handle = #dsohandle + lazy var idea: Idea = { fatalError() }() +} + +struct Place { + let person: Person + let street: String + let apartment: Optional + let city: String + let state: String + let postalCode: Int + let plusFour: Int? +} + +protocol Thing { + var idea: Idea { get } +} + +enum Idea { + var subject: String { fatalError() } +} + + + + diff --git a/test/refactoring/MemberwiseInit/Outputs/generate_memberwise/struct_members.swift.expected b/test/refactoring/MemberwiseInit/Outputs/generate_memberwise/struct_members.swift.expected new file mode 100644 index 0000000000000..f16631713528f --- /dev/null +++ b/test/refactoring/MemberwiseInit/Outputs/generate_memberwise/struct_members.swift.expected @@ -0,0 +1,41 @@ +class Person { + var firstName: String! + var lastName: String! + var age: Int! + var planet = "Earth", solarSystem = "Milky Way" + var avgHeight = 175 + let line = #line, file = #file, handle = #dsohandle + lazy var idea: Idea = { fatalError() }() +} + +struct Place { +internal init(person: Person, street: String, apartment: Optional, city: String, state: String, postalCode: Int, plusFour: Int?) { +self.person = person +self.street = street +self.apartment = apartment +self.city = city +self.state = state +self.postalCode = postalCode +self.plusFour = plusFour +} + + let person: Person + let street: String + let apartment: Optional + let city: String + let state: String + let postalCode: Int + let plusFour: Int? +} + +protocol Thing { + var idea: Idea { get } +} + +enum Idea { + var subject: String { fatalError() } +} + + + + diff --git a/test/refactoring/MemberwiseInit/class_members.swift b/test/refactoring/MemberwiseInit/class_members.swift deleted file mode 100644 index 78081b6b8f18a..0000000000000 --- a/test/refactoring/MemberwiseInit/class_members.swift +++ /dev/null @@ -1,11 +0,0 @@ -class Person { - var firstName: String! - var lastName: String! - var age: Int! - var planet = "Earth", solarSystem = "Milky Way" - var avgHeight = 175 -} - -// RUN: %empty-directory(%t.result) -// RUN: %refactor -memberwise-init -source-filename %s -pos=1:8 > %t.result/class_members.swift -// RUN: diff -u %S/Outputs/class_members/class_members.swift.expected %t.result/class_members.swift diff --git a/test/refactoring/MemberwiseInit/generate_memberwise.swift b/test/refactoring/MemberwiseInit/generate_memberwise.swift new file mode 100644 index 0000000000000..f63e7294dc914 --- /dev/null +++ b/test/refactoring/MemberwiseInit/generate_memberwise.swift @@ -0,0 +1,38 @@ +class Person { + var firstName: String! + var lastName: String! + var age: Int! + var planet = "Earth", solarSystem = "Milky Way" + var avgHeight = 175 + let line = #line, file = #file, handle = #dsohandle + lazy var idea: Idea = { fatalError() }() +} + +struct Place { + let person: Person + let street: String + let apartment: Optional + let city: String + let state: String + let postalCode: Int + let plusFour: Int? +} + +protocol Thing { + var idea: Idea { get } +} + +enum Idea { + var subject: String { fatalError() } +} + +// RUN: %empty-directory(%t.result) +// RUN: %refactor -memberwise-init -source-filename %s -pos=1:8 > %t.result/generate_memberwise.swift +// RUN: diff -u %S/Outputs/generate_memberwise/class_members.swift.expected %t.result/generate_memberwise.swift + +// RUN: %refactor -memberwise-init -source-filename %s -pos=11:8 > %t.result/struct_members.swift +// RUN: diff -u %S/Outputs/generate_memberwise/struct_members.swift.expected %t.result/struct_members.swift + +// RUN: not %refactor -memberwise-init -source-filename %s -pos=21:10 > %t.result/protocol_members.swift +// RUN: not %refactor -memberwise-init -source-filename %s -pos=25:6 > %t.result/enum_members.swift + From 3146eed6a8cfdd75049af3338c86ce5c7c873e9a Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Fri, 6 Sep 2019 18:31:26 +0100 Subject: [PATCH 003/199] Revert "Revert "[Sema] Setter has incorrect mutating-ness inside class-constrained protocol extension"" This reverts commit edb153afd1d71fb869c4add80d0b47451092d62b. --- lib/Sema/TypeCheckDecl.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 46e4431ac2c06..8c506d94eccea 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -1957,8 +1957,17 @@ void TypeChecker::validateDecl(OperatorDecl *OD) { } bool swift::doesContextHaveValueSemantics(DeclContext *dc) { - if (Type contextTy = dc->getDeclaredInterfaceType()) - return !contextTy->hasReferenceSemantics(); + if (Type contextTy = dc->getDeclaredInterfaceType()) { + // If the decl context is an extension, then it could be imposing a class + // constraint (ex: where Self: SomeClass). Make sure we include that + // in our check as well. + auto extensionRequiresClass = false; + if (auto ED = dyn_cast(dc)) { + extensionRequiresClass = + ED->getGenericSignature()->requiresClass(ED->getSelfInterfaceType()); + } + return !contextTy->hasReferenceSemantics() && !extensionRequiresClass; + } return false; } From fc6a49e834f1c237347dfe277b2b85afeef9fc79 Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Fri, 6 Sep 2019 18:37:11 +0100 Subject: [PATCH 004/199] [Test] Update tests --- test/decl/ext/extensions.swift | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/decl/ext/extensions.swift b/test/decl/ext/extensions.swift index dc8e3d42d597f..689963b7ad25e 100644 --- a/test/decl/ext/extensions.swift +++ b/test/decl/ext/extensions.swift @@ -126,7 +126,7 @@ struct WrapperContext { } // Class-constrained extension where protocol does not impose class requirement - +// SR-11298 protocol DoesNotImposeClassReq_1 {} class JustAClass: DoesNotImposeClassReq_1 { @@ -140,8 +140,8 @@ extension DoesNotImposeClassReq_1 where Self: JustAClass { } } -let instanceOfJustAClass = JustAClass() // expected-note {{change 'let' to 'var' to make it mutable}} -instanceOfJustAClass.wrappingProperty = "" // expected-error {{cannot assign to property: 'instanceOfJustAClass' is a 'let' constant}} +let instanceOfJustAClass = JustAClass() +instanceOfJustAClass.wrappingProperty = "" // Okay protocol DoesNotImposeClassReq_2 { var property: String { get set } @@ -150,6 +150,7 @@ protocol DoesNotImposeClassReq_2 { extension DoesNotImposeClassReq_2 where Self : AnyObject { var wrappingProperty: String { get { property } - set { property = newValue } // Okay + set { property = newValue } // expected-error {{cannot assign to property: 'self' is immutable}} + // expected-note@-1 {{mark accessor 'mutating' to make 'self' mutable}} } } From d4c21cf188746f5bc1880cced8ad6e78f022da96 Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Fri, 6 Sep 2019 18:50:42 +0100 Subject: [PATCH 005/199] [Changelog] Add a changelog entry --- CHANGELOG.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e0bd999e419e..7165889fcad62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,9 +26,32 @@ CHANGELOG Swift Next ---------- +* [SR-11298][]: + + A class-constrained protocol extension, where the extended protocol does + not impose a class constraint, will now infer the constraint implicitly. + + ```swift + protocol Foo {} + class Bar: Foo { + var someProperty: Int = 0 + } + + // Even though 'Foo' does not impose a class constraint, it is automatically + // inferred due to the Self: Bar constraint. + extension Foo where Self: Bar { + var anotherProperty: Int { + get { return someProperty } + // As a result, the setter is now implicitly nonmutating, just like it would + // be if 'Foo' had a class constraint. + set { someProperty = newValue } + } + } + ``` + * [SR-4206][]: - A method override is no longer allowed to have a generic signature with + A method override is no longer allowed to have a generic signature with requirements not imposed by the base method. For example: ``` @@ -7741,3 +7764,4 @@ Swift 1.0 [SR-8974]: [SR-9043]: [SR-9827]: +[SR-11298]: From e8d288e6aeb826db98b959c44042dac5c8950793 Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Fri, 6 Sep 2019 19:30:38 +0100 Subject: [PATCH 006/199] [Changelog] Add an example for the broken case --- CHANGELOG.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7165889fcad62..8da1997577bf6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,33 @@ Swift Next } } ``` + + As a result, this could lead to code that currently compiles today to throw an error. + + ```swift + protocol Foo { + var someProperty: Int { get set } + } + + class Bar: Foo { + var someProperty = 0 + } + + extension Foo where Self: Bar { + var anotherProperty1: Int { + get { return someProperty } + // 'someProperty' exists as a protocol requirement (implicitly mutating + // due to the lack of a class constraint), so the setter below needs to + // be explicitly marked as 'mutating'. + set { someProperty = newValue } // Error + } + + var anotherProperty2: Int { + get { return someProperty } + mutating set { someProperty = newValue } // Okay + } + } + ``` * [SR-4206][]: From 54a4615e6f9e5e723ee1a8f933e94e0a9d047248 Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Fri, 6 Sep 2019 23:40:07 +0100 Subject: [PATCH 007/199] [Diagnostics] Do not offer a mutating fix-it if we have a mutating protocol requirement Do not offer a mutating fix-it if we have a mutating protocol requirement and we're assigning to it from an implicitly nonmutating setter inside a protocol extension --- include/swift/AST/Decl.h | 3 ++- lib/AST/Decl.cpp | 26 +++++++++++++++++++++++--- lib/Sema/CSDiagnostics.cpp | 15 ++++++++++++--- test/decl/ext/extensions.swift | 1 - 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index bb981d4dece90..f7e8b46ccdbab 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -5131,7 +5131,8 @@ class VarDecl : public AbstractStorageDecl { /// If this is a simple 'let' constant, emit a note with a fixit indicating /// that it can be rewritten to a 'var'. This is used in situations where the /// compiler detects obvious attempts to mutate a constant. - void emitLetToVarNoteIfSimple(DeclContext *UseDC) const; + void emitLetToVarNoteIfSimple(DeclContext *UseDC, + ValueDecl *Anchor = nullptr) const; /// Returns true if the name is the self identifier and is implicit. bool isSelfParameter() const; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 298de47484443..9cd199a4c44ac 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -5689,7 +5689,8 @@ ObjCSelector VarDecl::getDefaultObjCSetterSelector(ASTContext &ctx, /// If this is a simple 'let' constant, emit a note with a fixit indicating /// that it can be rewritten to a 'var'. This is used in situations where the /// compiler detects obvious attempts to mutate a constant. -void VarDecl::emitLetToVarNoteIfSimple(DeclContext *UseDC) const { +void VarDecl::emitLetToVarNoteIfSimple(DeclContext *UseDC, + ValueDecl *Anchor) const { // If it isn't a 'let', don't touch it. if (!isLet()) return; @@ -5703,12 +5704,31 @@ void VarDecl::emitLetToVarNoteIfSimple(DeclContext *UseDC) const { if (FD && !FD->isMutating() && !FD->isImplicit() && FD->isInstanceMember()&& !FD->getDeclContext()->getDeclaredInterfaceType() ->hasReferenceSemantics()) { - // Do not suggest the fix it in implicit getters + // Do not suggest the fix-it in implicit getters if (auto AD = dyn_cast(FD)) { if (AD->isGetter() && !AD->getAccessorKeywordLoc().isValid()) return; + + // Do not suggest the fix-it if we have an implicitly nonmutating + // setter in a protocol extension and we're assigning to a mutating + // protocol requirement. + if (Anchor && Anchor->isProtocolRequirement() && isa(Anchor)) { + auto requirementVar = cast(Anchor); + auto innermostTyCtx = AD->getInnermostTypeContext(); + bool isRequirementSetterMutating = requirementVar->isSetterMutating(); + bool isProtoExtension = + innermostTyCtx + ? innermostTyCtx->getExtendedProtocolDecl() != nullptr + : false; + bool isImplicitlyNonMutatingSetter = + AD->isSetter() && AD->isNonMutating() && + !AD->getAttrs().hasAttribute(); + if (isRequirementSetterMutating && isProtoExtension && + isImplicitlyNonMutatingSetter) + return; + } } - + auto &d = getASTContext().Diags; d.diagnose(FD->getFuncLoc(), diag::change_to_mutating, isa(FD)) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index bcc244fe09c25..dd86132ea7b99 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -1468,9 +1468,18 @@ bool AssignmentFailure::diagnoseAsError() { } } - // If this is a simple variable marked with a 'let', emit a note to fixit - // hint it to 'var'. - VD->emitLetToVarNoteIfSimple(DC); + // If this is a simple variable marked with a 'let', emit a note to change + // it to 'var'. + // + // We also need a reference to the overload for the anchor, because it's + // possible that we're assigning to a mutating protocol property from an + // implicitly nonmutating setter in a protocol extension. In that case, + // we want to drop the fix-it to add 'mutating' as it's gonna re-trigger + // this error. + auto overload = + getConstraintSystem().findSelectedOverloadFor(getAnchor()); + auto anchor = overload ? overload->Choice.getDeclOrNull() : nullptr; + VD->emitLetToVarNoteIfSimple(DC, anchor); return true; } diff --git a/test/decl/ext/extensions.swift b/test/decl/ext/extensions.swift index 3ac2b3d86b43f..1dd8801709b95 100644 --- a/test/decl/ext/extensions.swift +++ b/test/decl/ext/extensions.swift @@ -151,7 +151,6 @@ extension DoesNotImposeClassReq_2 where Self : AnyObject { var wrappingProperty: String { get { property } set { property = newValue } // expected-error {{cannot assign to property: 'self' is immutable}} - // expected-note@-1 {{mark accessor 'mutating' to make 'self' mutable}} } } From c31b18490754add177d7509b945b0a2b66fe8ad3 Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Fri, 6 Sep 2019 23:45:32 +0100 Subject: [PATCH 008/199] [Changelog] Update changelog --- CHANGELOG.md | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95717ac18db29..b4871ed825569 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,19 +63,16 @@ Swift Next extension Foo where Self: Bar { var anotherProperty1: Int { get { return someProperty } - // 'someProperty' exists as a protocol requirement (implicitly mutating - // due to the lack of a class constraint), so the setter below needs to - // be explicitly marked as 'mutating'. - set { someProperty = newValue } // Error - } - - var anotherProperty2: Int { - get { return someProperty } - mutating set { someProperty = newValue } // Okay + // This will now error, because the protocol requirement + // is implicitly mutating and the setter is implicitly + // nonmutating. + set { someProperty = newValue } } } ``` + To resolve this, explicitly mark the setter as `nonmutating` in the protocol. + * [SE-0253][]: Values of types that declare `func callAsFunction` methods can be called From 7691fbdc766166c51d0fd34200f3e05fe37499fd Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Sat, 7 Sep 2019 02:18:07 +0100 Subject: [PATCH 009/199] [Changelog] Add workaround for nonmutating setter --- CHANGELOG.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4871ed825569..4294059ee5c95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,12 +66,22 @@ Swift Next // This will now error, because the protocol requirement // is implicitly mutating and the setter is implicitly // nonmutating. - set { someProperty = newValue } + set { someProperty = newValue } // Error } } ``` - To resolve this, explicitly mark the setter as `nonmutating` in the protocol. + **Workaround**: Define a new mutable property inside the setter that has a reference to `self`: + + ```swift + var anotherProperty1: Int { + get { return someProperty } + set { + var mutableSelf = self + mutableSelf.someProperty = newValue // Okay + } + } +``` * [SE-0253][]: From b2547417b6eff47f968cd3e593d5d23abd685c6d Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Sat, 7 Sep 2019 02:32:23 +0100 Subject: [PATCH 010/199] [Changelog] Change 'mutable property' to 'mutable variable' --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4294059ee5c95..e5f77111a401b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -71,7 +71,7 @@ Swift Next } ``` - **Workaround**: Define a new mutable property inside the setter that has a reference to `self`: + **Workaround**: Define a new mutable variable inside the setter that has a reference to `self`: ```swift var anotherProperty1: Int { From f676dde8029b569476fb3db00195a69e30e341e5 Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Mon, 9 Sep 2019 19:41:51 +0100 Subject: [PATCH 011/199] [Typechecker] Use a 'is Self class-bound?' check instead --- include/swift/AST/Decl.h | 3 +-- lib/AST/Decl.cpp | 25 ++++++------------------- lib/Sema/CSDiagnostics.cpp | 15 +++------------ 3 files changed, 10 insertions(+), 33 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index f7e8b46ccdbab..bb981d4dece90 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -5131,8 +5131,7 @@ class VarDecl : public AbstractStorageDecl { /// If this is a simple 'let' constant, emit a note with a fixit indicating /// that it can be rewritten to a 'var'. This is used in situations where the /// compiler detects obvious attempts to mutate a constant. - void emitLetToVarNoteIfSimple(DeclContext *UseDC, - ValueDecl *Anchor = nullptr) const; + void emitLetToVarNoteIfSimple(DeclContext *UseDC) const; /// Returns true if the name is the self identifier and is implicit. bool isSelfParameter() const; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 9cd199a4c44ac..5e7442cc6deab 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -5689,8 +5689,7 @@ ObjCSelector VarDecl::getDefaultObjCSetterSelector(ASTContext &ctx, /// If this is a simple 'let' constant, emit a note with a fixit indicating /// that it can be rewritten to a 'var'. This is used in situations where the /// compiler detects obvious attempts to mutate a constant. -void VarDecl::emitLetToVarNoteIfSimple(DeclContext *UseDC, - ValueDecl *Anchor) const { +void VarDecl::emitLetToVarNoteIfSimple(DeclContext *UseDC) const { // If it isn't a 'let', don't touch it. if (!isLet()) return; @@ -5709,23 +5708,11 @@ void VarDecl::emitLetToVarNoteIfSimple(DeclContext *UseDC, if (AD->isGetter() && !AD->getAccessorKeywordLoc().isValid()) return; - // Do not suggest the fix-it if we have an implicitly nonmutating - // setter in a protocol extension and we're assigning to a mutating - // protocol requirement. - if (Anchor && Anchor->isProtocolRequirement() && isa(Anchor)) { - auto requirementVar = cast(Anchor); - auto innermostTyCtx = AD->getInnermostTypeContext(); - bool isRequirementSetterMutating = requirementVar->isSetterMutating(); - bool isProtoExtension = - innermostTyCtx - ? innermostTyCtx->getExtendedProtocolDecl() != nullptr - : false; - bool isImplicitlyNonMutatingSetter = - AD->isSetter() && AD->isNonMutating() && - !AD->getAttrs().hasAttribute(); - if (isRequirementSetterMutating && isProtoExtension && - isImplicitlyNonMutatingSetter) - return; + // Do not suggest the fix-it if `Self` is a class type. + if (AD->getDeclContext() + ->getSelfTypeInContext() + ->isAnyClassReferenceType()) { + return; } } diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index dd86132ea7b99..bcc244fe09c25 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -1468,18 +1468,9 @@ bool AssignmentFailure::diagnoseAsError() { } } - // If this is a simple variable marked with a 'let', emit a note to change - // it to 'var'. - // - // We also need a reference to the overload for the anchor, because it's - // possible that we're assigning to a mutating protocol property from an - // implicitly nonmutating setter in a protocol extension. In that case, - // we want to drop the fix-it to add 'mutating' as it's gonna re-trigger - // this error. - auto overload = - getConstraintSystem().findSelectedOverloadFor(getAnchor()); - auto anchor = overload ? overload->Choice.getDeclOrNull() : nullptr; - VD->emitLetToVarNoteIfSimple(DC, anchor); + // If this is a simple variable marked with a 'let', emit a note to fixit + // hint it to 'var'. + VD->emitLetToVarNoteIfSimple(DC); return true; } From 29ca8b0b38157dcc972989781ba044dde3fc102c Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Mon, 9 Sep 2019 21:17:27 +0100 Subject: [PATCH 012/199] [AST] Adds 'hasValueSemantics()' to DeclContext and uses 'getSelfTypeInContext()' instead --- include/swift/AST/DeclContext.h | 5 ++++- lib/AST/Decl.cpp | 4 +--- lib/AST/DeclContext.cpp | 8 ++++++++ lib/Sema/TypeCheckDecl.cpp | 21 ++------------------- lib/Sema/TypeCheckDecl.h | 2 -- lib/Sema/TypeCheckStorage.cpp | 8 ++++---- 6 files changed, 19 insertions(+), 29 deletions(-) diff --git a/include/swift/AST/DeclContext.h b/include/swift/AST/DeclContext.h index 7580ddcb78164..72af7aeaf224b 100644 --- a/include/swift/AST/DeclContext.h +++ b/include/swift/AST/DeclContext.h @@ -261,7 +261,10 @@ class alignas(1 << DeclContextAlignInBits) DeclContext { /// Returns the kind of context this is. DeclContextKind getContextKind() const; - + + /// Returns whether this context has value semantics. + bool hasValueSemantics() const; + /// Determines whether this context is itself a local scope in a /// code block. A context that appears in such a scope, like a /// local type declaration, does not itself become a local context. diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 5e7442cc6deab..fc9d1b1dd78a8 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -5709,9 +5709,7 @@ void VarDecl::emitLetToVarNoteIfSimple(DeclContext *UseDC) const { return; // Do not suggest the fix-it if `Self` is a class type. - if (AD->getDeclContext() - ->getSelfTypeInContext() - ->isAnyClassReferenceType()) { + if (!AD->getDeclContext()->hasValueSemantics()) { return; } } diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index 6d2f9d761995b..e70e7ebf088e3 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -1024,6 +1024,14 @@ DeclContextKind DeclContext::getContextKind() const { llvm_unreachable("Unhandled DeclContext ASTHierarchy"); } +bool DeclContext::hasValueSemantics() const { + if (auto contextTy = getSelfTypeInContext()) { + return !contextTy->hasReferenceSemantics(); + } + + return false; +} + SourceLoc swift::extractNearestSourceLoc(const DeclContext *dc) { switch (dc->getContextKind()) { case DeclContextKind::AbstractFunctionDecl: diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index d4e7436570621..8c578ca5316bb 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -1956,26 +1956,10 @@ void TypeChecker::validateDecl(OperatorDecl *OD) { } } -bool swift::doesContextHaveValueSemantics(DeclContext *dc) { - if (Type contextTy = dc->getDeclaredInterfaceType()) { - // If the decl context is an extension, then it could be imposing a class - // constraint (ex: where Self: SomeClass). Make sure we include that - // in our check as well. - auto extensionRequiresClass = false; - if (auto ED = dyn_cast(dc)) { - extensionRequiresClass = - ED->getGenericSignature()->requiresClass(ED->getSelfInterfaceType()); - } - return !contextTy->hasReferenceSemantics() && !extensionRequiresClass; - } - return false; -} - llvm::Expected SelfAccessKindRequest::evaluate(Evaluator &evaluator, FuncDecl *FD) const { if (FD->getAttrs().getAttribute(true)) { - if (!FD->isInstanceMember() || - !doesContextHaveValueSemantics(FD->getDeclContext())) { + if (!FD->isInstanceMember() || !FD->getDeclContext()->hasValueSemantics()) { return SelfAccessKind::NonMutating; } return SelfAccessKind::Mutating; @@ -1997,8 +1981,7 @@ SelfAccessKindRequest::evaluate(Evaluator &evaluator, FuncDecl *FD) const { case AccessorKind::MutableAddress: case AccessorKind::Set: case AccessorKind::Modify: - if (AD->isInstanceMember() && - doesContextHaveValueSemantics(AD->getDeclContext())) + if (AD->isInstanceMember() && AD->getDeclContext()->hasValueSemantics()) return SelfAccessKind::Mutating; break; diff --git a/lib/Sema/TypeCheckDecl.h b/lib/Sema/TypeCheckDecl.h index f546f78762fe9..d6eaeaf17b828 100644 --- a/lib/Sema/TypeCheckDecl.h +++ b/lib/Sema/TypeCheckDecl.h @@ -25,8 +25,6 @@ class DeclContext; class ValueDecl; class Pattern; -bool doesContextHaveValueSemantics(DeclContext *dc); - /// Walks up the override chain for \p CD until it finds an initializer that is /// required and non-implicit. If no such initializer exists, returns the /// declaration where \c required was introduced (i.e. closest to the root diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index 5d71c7a9b34ab..95c2b8428e208 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -268,8 +268,8 @@ void swift::validatePatternBindingEntries(TypeChecker &tc, llvm::Expected IsGetterMutatingRequest::evaluate(Evaluator &evaluator, AbstractStorageDecl *storage) const { - bool result = (!storage->isStatic() && - doesContextHaveValueSemantics(storage->getDeclContext())); + bool result = + (!storage->isStatic() && storage->getDeclContext()->hasValueSemantics()); // 'lazy' overrides the normal accessor-based rules and heavily // restricts what accessors can be used. The getter is considered @@ -323,8 +323,8 @@ IsSetterMutatingRequest::evaluate(Evaluator &evaluator, AbstractStorageDecl *storage) const { // By default, the setter is mutating if we have an instance member of a // value type, but this can be overridden below. - bool result = (!storage->isStatic() && - doesContextHaveValueSemantics(storage->getDeclContext())); + bool result = + (!storage->isStatic() && storage->getDeclContext()->hasValueSemantics()); // If we have an attached property wrapper, the setter is mutating // or not based on the composition of the wrappers. From e8fe05d9bb3f98d54e7bf5cdc24c053cd619d40a Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Wed, 11 Sep 2019 01:03:22 +0100 Subject: [PATCH 013/199] [AST] hasValueSemantics() should check whether the current context is a type context before proceeding --- lib/AST/DeclContext.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index e70e7ebf088e3..4085edbe3fca3 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -1025,6 +1025,9 @@ DeclContextKind DeclContext::getContextKind() const { } bool DeclContext::hasValueSemantics() const { + if (!isTypeContext()) + return false; + if (auto contextTy = getSelfTypeInContext()) { return !contextTy->hasReferenceSemantics(); } From 40985b6eb7d8e1923a25d5c005783ce4e54cbc01 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Fri, 13 Sep 2019 14:51:17 -0700 Subject: [PATCH 014/199] [Diagnostics] Generalize the "protocol type cannot conform" error to work for all types that cannot conform to protocols. --- include/swift/AST/DiagnosticsSema.def | 7 +++--- lib/Sema/CSDiagnostics.cpp | 25 ++++++++++++++----- lib/Sema/TypeCheckProtocol.cpp | 2 +- test/Constraints/diagnostics.swift | 4 +-- test/Constraints/function_builder_diags.swift | 4 +-- test/Constraints/generics.swift | 2 +- test/Constraints/operator.swift | 2 +- .../conditional_conformances_literals.swift | 4 +-- test/Generics/existential_restrictions.swift | 12 ++++----- .../conforms/error_self_conformance.swift | 6 ++--- test/stmt/foreach.swift | 2 +- test/type/opaque.swift | 3 +-- test/type/subclass_composition.swift | 2 +- .../rdar27830834.swift | 2 +- .../0196-rdar48937223.swift | 4 +-- ...set-llvm-attributesetnode-nodeequals.swift | 2 +- 16 files changed, 47 insertions(+), 36 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 43a38aab36ce4..cb72735308779 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1660,10 +1660,9 @@ ERROR(cannot_use_nil_with_this_type,none, ERROR(use_of_equal_instead_of_equality,none, "use of '=' in a boolean context, did you mean '=='?", ()) - -ERROR(protocol_does_not_conform_objc,none, - "protocol type %0 cannot conform to %1 because only concrete " - "types can conform to protocols", (Type, Type)) +ERROR(type_cannot_conform, none, + "%0 type %1 cannot conform to %2; only struct/enum/class " + "types can conform to protocols", (StringRef, Type, Type)) ERROR(protocol_does_not_conform_static,none, "%0 cannot be used as a type conforming to protocol %1 because %1 " "has static requirements", diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 2e4997ad44573..ce38aac992347 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -570,13 +570,26 @@ bool MissingConformanceFailure::diagnoseAsError() { } } - if (nonConformingType->isExistentialType()) { - auto diagnostic = diag::protocol_does_not_conform_objc; - if (nonConformingType->isObjCExistentialType()) - diagnostic = diag::protocol_does_not_conform_static; + if (nonConformingType->isObjCExistentialType()) { + emitDiagnostic(anchor->getLoc(), diag::protocol_does_not_conform_static, + nonConformingType, protocolType); + return true; + } - emitDiagnostic(anchor->getLoc(), diagnostic, nonConformingType, - protocolType); + // Diagnose types that cannot conform to protocols. + Optional prohibitedTypeKind = None; + if (nonConformingType->is()) + prohibitedTypeKind = "function"; + else if (nonConformingType->is()) + prohibitedTypeKind = "tuple"; + else if (nonConformingType->isExistentialType()) + prohibitedTypeKind = "protocol"; + else if (nonConformingType->is()) + prohibitedTypeKind = "metatype"; + + if (prohibitedTypeKind.hasValue()) { + emitDiagnostic(anchor->getLoc(), diag::type_cannot_conform, + *prohibitedTypeKind, nonConformingType, protocolType); return true; } diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 346cac8f70d42..e5010c2002df6 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -3970,7 +3970,7 @@ static void diagnoseConformanceFailure(Type T, TypeChecker::containsProtocol(T, Proto, DC, None)) { if (!T->isObjCExistentialType()) { - diags.diagnose(ComplainLoc, diag::protocol_does_not_conform_objc, + diags.diagnose(ComplainLoc, diag::type_cannot_conform, "protocol", T, Proto->getDeclaredType()); return; } diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index aa36ca21a5c8b..8c46f9d06debe 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -47,7 +47,7 @@ f0(i, i, // Position mismatch -f5(f4) // expected-error {{argument type '(Int) -> Int' does not conform to expected type 'P2'}} +f5(f4) // expected-error {{function type '(Int) -> Int' cannot conform to 'P2'; only struct/enum/class types can conform to protocols}} // Tuple element not convertible. f0(i, @@ -97,7 +97,7 @@ func f8(_ n: T, _ f: @escaping (T) -> T) {} f8(3, f4) // expected-error {{argument type 'Int' does not conform to expected type 'P2'}} typealias Tup = (Int, Double) func f9(_ x: Tup) -> Tup { return x } -f8((1,2.0), f9) // expected-error {{argument type 'Tup' (aka '(Int, Double)') does not conform to expected type 'P2'}} +f8((1,2.0), f9) // expected-error {{tuple type 'Tup' (aka '(Int, Double)') cannot conform to 'P2'; only struct/enum/class types can conform to protocols}} // QoI: Incorrect diagnostic for calling nonexistent members on literals 1.doesntExist(0) // expected-error {{value of type 'Int' has no member 'doesntExist'}} diff --git a/test/Constraints/function_builder_diags.swift b/test/Constraints/function_builder_diags.swift index e88268dcd53d2..47800391e4303 100644 --- a/test/Constraints/function_builder_diags.swift +++ b/test/Constraints/function_builder_diags.swift @@ -144,7 +144,7 @@ struct TupleP : P { @_functionBuilder struct Builder { - static func buildBlock(_ stmt1: S0, _ stmt2: S1) // expected-note {{where 'S1' = 'Label.Type'}} + static func buildBlock(_ stmt1: S0, _ stmt2: S1) -> TupleP<(S0, S1)> where S0: P, S1: P { return TupleP((stmt1, stmt2)) } @@ -166,7 +166,7 @@ struct Label : P where L : P { // expected-note {{'L' declared as parameter t } func test_51167632() -> some P { - AnyP(G { // expected-error {{static method 'buildBlock' requires that 'Label.Type' conform to 'P'}} + AnyP(G { // expected-error {{metatype type 'Label.Type' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} Text("hello") Label // expected-error {{generic parameter 'L' could not be inferred}} // expected-note@-1 {{explicitly specify the generic arguments to fix this issue}} {{10-10=<<#L: P#>>}} diff --git a/test/Constraints/generics.swift b/test/Constraints/generics.swift index 9c56f64736701..b75400ed550ba 100644 --- a/test/Constraints/generics.swift +++ b/test/Constraints/generics.swift @@ -191,7 +191,7 @@ func r22459135() { // QoI: Friendlier error message for "[] as Set" // QoI: "argument for generic parameter 'Element' could not be inferred" lacks context -_ = [] as Set // expected-error {{protocol type 'Any' cannot conform to 'Hashable' because only concrete types can conform to protocols}} +_ = [] as Set // expected-error {{protocol type 'Any' cannot conform to 'Hashable'; only struct/enum/class types can conform to protocols}} // QoI: Error when unable to infer generic archetype lacks greatness diff --git a/test/Constraints/operator.swift b/test/Constraints/operator.swift index ca26d1a366bd3..b84b827205f65 100644 --- a/test/Constraints/operator.swift +++ b/test/Constraints/operator.swift @@ -220,7 +220,7 @@ func rdar46459603() { // expected-error@-1 {{binary operator '==' cannot be applied to operands of type 'Dictionary.Values' and '[E]'}} // expected-note@-2 {{expected an argument list of type '(Self, Self)'}} _ = [arr.values] == [[e]] - // expected-error@-1 {{protocol type 'Any' cannot conform to 'Equatable' because only concrete types can conform to protocols}} + // expected-error@-1 {{protocol type 'Any' cannot conform to 'Equatable'; only struct/enum/class types can conform to protocols}} } // SR-10843 diff --git a/test/Generics/conditional_conformances_literals.swift b/test/Generics/conditional_conformances_literals.swift index 5bb0c3726f923..a59fba4550f54 100644 --- a/test/Generics/conditional_conformances_literals.swift +++ b/test/Generics/conditional_conformances_literals.swift @@ -127,9 +127,9 @@ func combined() { // Needs self conforming protocols: let _: Conforms = [[0: [1 : [works]] as Conforms]] - // expected-error@-1 {{protocol type 'Conforms' cannot conform to 'Conforms' because only concrete types can conform to protocols}} + // expected-error@-1 {{protocol type 'Conforms' cannot conform to 'Conforms'; only struct/enum/class types can conform to protocols}} let _: Conforms = [[0: [1 : [fails]] as Conforms]] // expected-error@-1 {{protocol 'Conforms' requires that 'Fails' conform to 'Conforms'}} - // expected-error@-2 {{protocol type 'Conforms' cannot conform to 'Conforms' because only concrete types can conform to protocols}} + // expected-error@-2 {{protocol type 'Conforms' cannot conform to 'Conforms'; only struct/enum/class types can conform to protocols}} } diff --git a/test/Generics/existential_restrictions.swift b/test/Generics/existential_restrictions.swift index 9731372ae7f6e..c2ce683f69d24 100644 --- a/test/Generics/existential_restrictions.swift +++ b/test/Generics/existential_restrictions.swift @@ -17,7 +17,7 @@ func fAOE(_ t: AnyObject) { } func fT(_ t: T) { } func testPassExistential(_ p: P, op: OP, opp: OP & P, cp: CP, sp: SP, any: Any, ao: AnyObject) { - fP(p) // expected-error{{protocol type 'P' cannot conform to 'P' because only concrete types can conform to protocols}} + fP(p) // expected-error{{protocol type 'P' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} fAO(p) // expected-error{{cannot invoke 'fAO' with an argument list of type '(P)'}} // expected-note{{expected an argument list of type '(T)'}} fAOE(p) // expected-error{{argument type 'P' does not conform to expected type 'AnyObject'}} fT(p) @@ -31,8 +31,8 @@ func testPassExistential(_ p: P, op: OP, opp: OP & P, cp: CP, sp: SP, any: Any, fAOE(cp) fT(cp) - fP(opp) // expected-error{{protocol type 'OP & P' cannot conform to 'P' because only concrete types can conform to protocols}} - fOP(opp) // expected-error{{protocol type 'OP & P' cannot conform to 'OP' because only concrete types can conform to protocols}} + fP(opp) // expected-error{{protocol type 'OP & P' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} + fOP(opp) // expected-error{{protocol type 'OP & P' cannot conform to 'OP'; only struct/enum/class types can conform to protocols}} fAO(opp) // expected-error{{cannot invoke 'fAO' with an argument list of type '(OP & P)'}} // expected-note{{expected an argument list of type '(T)'}} fAOE(opp) fT(opp) @@ -58,9 +58,9 @@ class GAO {} // expected-note 2{{requirement specified as 'T' : ' func blackHole(_ t: Any) {} func testBindExistential() { - blackHole(GP

()) // expected-error{{protocol type 'P' cannot conform to 'P' because only concrete types can conform to protocols}} + blackHole(GP

()) // expected-error{{protocol type 'P' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} blackHole(GOP()) - blackHole(GCP()) // expected-error{{protocol type 'CP' cannot conform to 'CP' because only concrete types can conform to protocols}} + blackHole(GCP()) // expected-error{{protocol type 'CP' cannot conform to 'CP'; only struct/enum/class types can conform to protocols}} blackHole(GAO

()) // expected-error{{'GAO' requires that 'P' be a class type}} blackHole(GAO()) blackHole(GAO()) // expected-error{{'GAO' requires that 'CP' be a class type}} @@ -85,5 +85,5 @@ func foo() { // generic no overloads error path. The error should actually talk // about the return type, and this can happen in other contexts as well; // tracks improving QoI here. - allMine.takeAll() // expected-error{{protocol type 'Mine' cannot conform to 'Mine' because only concrete types can conform to protocols}} + allMine.takeAll() // expected-error{{protocol type 'Mine' cannot conform to 'Mine'; only struct/enum/class types can conform to protocols}} } diff --git a/test/decl/protocol/conforms/error_self_conformance.swift b/test/decl/protocol/conforms/error_self_conformance.swift index 7293d02b0288e..e1b2bcd68ed78 100644 --- a/test/decl/protocol/conforms/error_self_conformance.swift +++ b/test/decl/protocol/conforms/error_self_conformance.swift @@ -8,15 +8,15 @@ func testSimple(error: Error) { protocol ErrorRefinement : Error {} func testErrorRefinment(error: ErrorRefinement) { - wantsError(error) // expected-error {{protocol type 'ErrorRefinement' cannot conform to 'Error' because only concrete types can conform to protocols}} + wantsError(error) // expected-error {{protocol type 'ErrorRefinement' cannot conform to 'Error'; only struct/enum/class types can conform to protocols}} } protocol OtherProtocol {} func testErrorComposition(error: Error & OtherProtocol) { - wantsError(error) // expected-error {{protocol type 'Error & OtherProtocol' cannot conform to 'Error' because only concrete types can conform to protocols}} + wantsError(error) // expected-error {{protocol type 'Error & OtherProtocol' cannot conform to 'Error'; only struct/enum/class types can conform to protocols}} } class C {} func testErrorCompositionWithClass(error: Error & C) { - wantsError(error) // expected-error {{protocol type 'C & Error' cannot conform to 'Error' because only concrete types can conform to protocols}} + wantsError(error) // expected-error {{protocol type 'C & Error' cannot conform to 'Error'; only struct/enum/class types can conform to protocols}} } diff --git a/test/stmt/foreach.swift b/test/stmt/foreach.swift index 31da1bb1b7aeb..9b1b80b52ec4e 100644 --- a/test/stmt/foreach.swift +++ b/test/stmt/foreach.swift @@ -179,7 +179,7 @@ func testOptionalSequence() { // Crash with (invalid) for each over an existential func testExistentialSequence(s: Sequence) { // expected-error {{protocol 'Sequence' can only be used as a generic constraint because it has Self or associated type requirements}} - for x in s { // expected-error {{protocol type 'Sequence' cannot conform to 'Sequence' because only concrete types can conform to protocols}} + for x in s { // expected-error {{protocol type 'Sequence' cannot conform to 'Sequence'; only struct/enum/class types can conform to protocols}} _ = x } } diff --git a/test/type/opaque.swift b/test/type/opaque.swift index 5d91109329754..79101dd4b29f6 100644 --- a/test/type/opaque.swift +++ b/test/type/opaque.swift @@ -377,8 +377,7 @@ protocol P_51641323 { func rdar_51641323() { struct Foo: P_51641323 { var foo: some P_51641323 { {} } - // expected-error@-1 {{return type of property 'foo' requires that '() -> ()' conform to 'P_51641323'}} - // expected-note@-2 {{opaque return type declared here}} + // expected-error@-1 {{function type '() -> ()' cannot conform to 'P_51641323'; only struct/enum/class types can conform to protocols}} } } diff --git a/test/type/subclass_composition.swift b/test/type/subclass_composition.swift index e3e1e82420407..7fc6d48d6577d 100644 --- a/test/type/subclass_composition.swift +++ b/test/type/subclass_composition.swift @@ -412,7 +412,7 @@ func conformsTo & P2>( // expected-note@-2 {{expected an argument list of type '(T)'}} conformsToP1(p1) - // expected-error@-1 {{protocol type 'P1' cannot conform to 'P1' because only concrete types can conform to protocols}} + // expected-error@-1 {{protocol type 'P1' cannot conform to 'P1'; only struct/enum/class types can conform to protocols}} // FIXME: Following diagnostics are not great because when // `conformsTo*` methods are re-typechecked, they loose information diff --git a/validation-test/Sema/type_checker_crashers_fixed/rdar27830834.swift b/validation-test/Sema/type_checker_crashers_fixed/rdar27830834.swift index 49d441637fd73..76a2d225baca6 100644 --- a/validation-test/Sema/type_checker_crashers_fixed/rdar27830834.swift +++ b/validation-test/Sema/type_checker_crashers_fixed/rdar27830834.swift @@ -1,4 +1,4 @@ // RUN: %target-swift-frontend %s -typecheck -verify var d = [String:String]() -_ = "\(d.map{ [$0 : $0] })" // expected-error {{generic struct 'Dictionary' requires that '(key: String, value: String)' conform to 'Hashable'}} +_ = "\(d.map{ [$0 : $0] })" // expected-error {{tuple type '(key: String, value: String)' cannot conform to 'Hashable'; only struct/enum/class types can conform to protocols}} diff --git a/validation-test/compiler_crashers_2_fixed/0196-rdar48937223.swift b/validation-test/compiler_crashers_2_fixed/0196-rdar48937223.swift index a9a1f563ae693..b0d2b824d2659 100644 --- a/validation-test/compiler_crashers_2_fixed/0196-rdar48937223.swift +++ b/validation-test/compiler_crashers_2_fixed/0196-rdar48937223.swift @@ -2,10 +2,10 @@ protocol P {} -func fn(_ arg1: T, arg2: (T) -> U) {} // expected-note {{where 'U' = '()'}} +func fn(_ arg1: T, arg2: (T) -> U) {} func test(str: String) { - fn(str) { arg in // expected-error {{global function 'fn(_:arg2:)' requires that '()' conform to 'P'}} + fn(str) { arg in // expected-error {{tuple type '()' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} <#FOO#> // expected-error {{editor placeholder in source file}} } } diff --git a/validation-test/compiler_crashers_fixed/00017-llvm-foldingset-llvm-attributesetnode-nodeequals.swift b/validation-test/compiler_crashers_fixed/00017-llvm-foldingset-llvm-attributesetnode-nodeequals.swift index 522e701e659fb..371cf90e94a2d 100644 --- a/validation-test/compiler_crashers_fixed/00017-llvm-foldingset-llvm-attributesetnode-nodeequals.swift +++ b/validation-test/compiler_crashers_fixed/00017-llvm-foldingset-llvm-attributesetnode-nodeequals.swift @@ -19,4 +19,4 @@ extension Bool : BooleanProtocol { } func f(_ b: T) { } -f(true as BooleanProtocol) // expected-error {{protocol type 'BooleanProtocol' cannot conform to 'BooleanProtocol' because only concrete types can conform to protocols}} +f(true as BooleanProtocol) // expected-error {{protocol type 'BooleanProtocol' cannot conform to 'BooleanProtocol'; only struct/enum/class types can conform to protocols}} From 73a218fd8ad57e405fa35bef03d87acda9698927 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Fri, 13 Sep 2019 15:03:23 -0700 Subject: [PATCH 015/199] [Test] Add test cases for missing protocol conformance failures for non-nominal types. --- test/Constraints/diagnostics.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index 8c46f9d06debe..166b5bd73e503 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -46,8 +46,10 @@ f0(i, i, i) // expected-error{{extra argument in call}} -// Position mismatch +// Cannot conform to protocols. f5(f4) // expected-error {{function type '(Int) -> Int' cannot conform to 'P2'; only struct/enum/class types can conform to protocols}} +f5((1, "hello")) // expected-error {{tuple type '(Int, String)' cannot conform to 'P2'; only struct/enum/class types can conform to protocols}} +f5(Int.self) // expected-error {{metatype type 'Int.Type' cannot conform to 'P2'; only struct/enum/class types can conform to protocols}} // Tuple element not convertible. f0(i, From 4af9744fe3ac75c33208577837adbcef913529da Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Sun, 15 Sep 2019 17:57:46 +0100 Subject: [PATCH 016/199] [CS] NFC: Move simplifyLocator out of CSDiag We eventually want to get rid of CSDiag, but `simplifyLocator` is definitely something we want to keep around. --- lib/Sema/CSDiag.cpp | 196 ---------------------------------- lib/Sema/ConstraintSystem.cpp | 196 ++++++++++++++++++++++++++++++++++ 2 files changed, 196 insertions(+), 196 deletions(-) diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp index 28a4b59308459..889ab7f9239e8 100644 --- a/lib/Sema/CSDiag.cpp +++ b/lib/Sema/CSDiag.cpp @@ -74,202 +74,6 @@ static bool isUnresolvedOrTypeVarType(Type ty) { return ty->isTypeVariableOrMember() || ty->is(); } -/// Given a subpath of an old locator, compute its summary flags. -static unsigned recomputeSummaryFlags(ConstraintLocator *oldLocator, - ArrayRef path) { - if (oldLocator->getSummaryFlags() != 0) - return ConstraintLocator::getSummaryFlagsForPath(path); - return 0; -} - -ConstraintLocator * -constraints::simplifyLocator(ConstraintSystem &cs, ConstraintLocator *locator, - SourceRange &range) { - auto path = locator->getPath(); - auto anchor = locator->getAnchor(); - simplifyLocator(anchor, path, range); - - // If we didn't simplify anything, just return the input. - if (anchor == locator->getAnchor() && - path.size() == locator->getPath().size()) { - return locator; - } - - // Recompute the summary flags if we had any to begin with. This is - // necessary because we might remove e.g. tuple elements from the path. - unsigned summaryFlags = recomputeSummaryFlags(locator, path); - return cs.getConstraintLocator(anchor, path, summaryFlags); -} - -void constraints::simplifyLocator(Expr *&anchor, - ArrayRef &path, - SourceRange &range) { - range = SourceRange(); - - while (!path.empty()) { - switch (path[0].getKind()) { - case ConstraintLocator::ApplyArgument: { - // Extract application argument. - if (auto applyExpr = dyn_cast(anchor)) { - anchor = applyExpr->getArg(); - path = path.slice(1); - continue; - } - - if (auto subscriptExpr = dyn_cast(anchor)) { - anchor = subscriptExpr->getIndex(); - path = path.slice(1); - continue; - } - - if (auto objectLiteralExpr = dyn_cast(anchor)) { - anchor = objectLiteralExpr->getArg(); - path = path.slice(1); - continue; - } - - if (auto *UME = dyn_cast(anchor)) { - anchor = UME->getArgument(); - path = path.slice(1); - continue; - } - break; - } - - case ConstraintLocator::ApplyFunction: - // Extract application function. - if (auto applyExpr = dyn_cast(anchor)) { - anchor = applyExpr->getFn(); - path = path.slice(1); - continue; - } - - // The subscript itself is the function. - if (auto subscriptExpr = dyn_cast(anchor)) { - anchor = subscriptExpr; - path = path.slice(1); - continue; - } - - // The unresolved member itself is the function. - if (auto unresolvedMember = dyn_cast(anchor)) { - if (unresolvedMember->getArgument()) { - anchor = unresolvedMember; - path = path.slice(1); - continue; - } - } - - break; - - case ConstraintLocator::AutoclosureResult: - case ConstraintLocator::LValueConversion: - case ConstraintLocator::RValueAdjustment: - case ConstraintLocator::UnresolvedMember: - // Arguments in autoclosure positions, lvalue and rvalue adjustments, and - // scalar-to-tuple conversions, and unresolved members are - // implicit. - path = path.slice(1); - continue; - - case ConstraintLocator::NamedTupleElement: - case ConstraintLocator::TupleElement: { - // Extract tuple element. - auto elt = path[0].castTo(); - unsigned index = elt.getIndex(); - if (auto tupleExpr = dyn_cast(anchor)) { - if (index < tupleExpr->getNumElements()) { - anchor = tupleExpr->getElement(index); - path = path.slice(1); - continue; - } - } - - if (auto *CE = dyn_cast(anchor)) { - if (index < CE->getNumElements()) { - anchor = CE->getElement(index); - path = path.slice(1); - continue; - } - } - break; - } - - case ConstraintLocator::ApplyArgToParam: { - auto elt = path[0].castTo(); - // Extract tuple element. - if (auto tupleExpr = dyn_cast(anchor)) { - unsigned index = elt.getArgIdx(); - if (index < tupleExpr->getNumElements()) { - anchor = tupleExpr->getElement(index); - path = path.slice(1); - continue; - } - } - - // Extract subexpression in parentheses. - if (auto parenExpr = dyn_cast(anchor)) { - assert(elt.getArgIdx() == 0); - - anchor = parenExpr->getSubExpr(); - path = path.slice(1); - continue; - } - break; - } - case ConstraintLocator::ConstructorMember: - if (auto typeExpr = dyn_cast(anchor)) { - // This is really an implicit 'init' MemberRef, so point at the base, - // i.e. the TypeExpr. - range = SourceRange(); - anchor = typeExpr; - path = path.slice(1); - continue; - } - LLVM_FALLTHROUGH; - - case ConstraintLocator::Member: - case ConstraintLocator::MemberRefBase: - if (auto UDE = dyn_cast(anchor)) { - range = UDE->getNameLoc().getSourceRange(); - anchor = UDE->getBase(); - path = path.slice(1); - continue; - } - break; - - case ConstraintLocator::SubscriptMember: - if (isa(anchor)) { - path = path.slice(1); - continue; - } - break; - - case ConstraintLocator::ClosureResult: - if (auto CE = dyn_cast(anchor)) { - if (CE->hasSingleExpressionBody()) { - anchor = CE->getSingleExpressionBody(); - path = path.slice(1); - continue; - } - } - break; - - case ConstraintLocator::ContextualType: - // This was just for identifying purposes, strip it off. - path = path.slice(1); - continue; - - default: - // FIXME: Lots of other cases to handle. - break; - } - - // If we get here, we couldn't simplify the path further. - break; - } -} - /// Flags that can be used to control name lookup. enum TCCFlags { /// Allow the result of the subexpression to be an lvalue. If this is not diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 6ef058e94d121..3ad8183ea55cb 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -2731,6 +2731,202 @@ bool ConstraintSystem::diagnoseAmbiguity(Expr *expr, return false; } +/// Given a subpath of an old locator, compute its summary flags. +static unsigned recomputeSummaryFlags(ConstraintLocator *oldLocator, + ArrayRef path) { + if (oldLocator->getSummaryFlags() != 0) + return ConstraintLocator::getSummaryFlagsForPath(path); + return 0; +} + +ConstraintLocator * +constraints::simplifyLocator(ConstraintSystem &cs, ConstraintLocator *locator, + SourceRange &range) { + auto path = locator->getPath(); + auto anchor = locator->getAnchor(); + simplifyLocator(anchor, path, range); + + // If we didn't simplify anything, just return the input. + if (anchor == locator->getAnchor() && + path.size() == locator->getPath().size()) { + return locator; + } + + // Recompute the summary flags if we had any to begin with. This is + // necessary because we might remove e.g. tuple elements from the path. + unsigned summaryFlags = recomputeSummaryFlags(locator, path); + return cs.getConstraintLocator(anchor, path, summaryFlags); +} + +void constraints::simplifyLocator(Expr *&anchor, + ArrayRef &path, + SourceRange &range) { + range = SourceRange(); + + while (!path.empty()) { + switch (path[0].getKind()) { + case ConstraintLocator::ApplyArgument: { + // Extract application argument. + if (auto applyExpr = dyn_cast(anchor)) { + anchor = applyExpr->getArg(); + path = path.slice(1); + continue; + } + + if (auto subscriptExpr = dyn_cast(anchor)) { + anchor = subscriptExpr->getIndex(); + path = path.slice(1); + continue; + } + + if (auto objectLiteralExpr = dyn_cast(anchor)) { + anchor = objectLiteralExpr->getArg(); + path = path.slice(1); + continue; + } + + if (auto *UME = dyn_cast(anchor)) { + anchor = UME->getArgument(); + path = path.slice(1); + continue; + } + break; + } + + case ConstraintLocator::ApplyFunction: + // Extract application function. + if (auto applyExpr = dyn_cast(anchor)) { + anchor = applyExpr->getFn(); + path = path.slice(1); + continue; + } + + // The subscript itself is the function. + if (auto subscriptExpr = dyn_cast(anchor)) { + anchor = subscriptExpr; + path = path.slice(1); + continue; + } + + // The unresolved member itself is the function. + if (auto unresolvedMember = dyn_cast(anchor)) { + if (unresolvedMember->getArgument()) { + anchor = unresolvedMember; + path = path.slice(1); + continue; + } + } + + break; + + case ConstraintLocator::AutoclosureResult: + case ConstraintLocator::LValueConversion: + case ConstraintLocator::RValueAdjustment: + case ConstraintLocator::UnresolvedMember: + // Arguments in autoclosure positions, lvalue and rvalue adjustments, and + // scalar-to-tuple conversions, and unresolved members are + // implicit. + path = path.slice(1); + continue; + + case ConstraintLocator::NamedTupleElement: + case ConstraintLocator::TupleElement: { + // Extract tuple element. + auto elt = path[0].castTo(); + unsigned index = elt.getIndex(); + if (auto tupleExpr = dyn_cast(anchor)) { + if (index < tupleExpr->getNumElements()) { + anchor = tupleExpr->getElement(index); + path = path.slice(1); + continue; + } + } + + if (auto *CE = dyn_cast(anchor)) { + if (index < CE->getNumElements()) { + anchor = CE->getElement(index); + path = path.slice(1); + continue; + } + } + break; + } + + case ConstraintLocator::ApplyArgToParam: { + auto elt = path[0].castTo(); + // Extract tuple element. + if (auto tupleExpr = dyn_cast(anchor)) { + unsigned index = elt.getArgIdx(); + if (index < tupleExpr->getNumElements()) { + anchor = tupleExpr->getElement(index); + path = path.slice(1); + continue; + } + } + + // Extract subexpression in parentheses. + if (auto parenExpr = dyn_cast(anchor)) { + assert(elt.getArgIdx() == 0); + + anchor = parenExpr->getSubExpr(); + path = path.slice(1); + continue; + } + break; + } + case ConstraintLocator::ConstructorMember: + if (auto typeExpr = dyn_cast(anchor)) { + // This is really an implicit 'init' MemberRef, so point at the base, + // i.e. the TypeExpr. + range = SourceRange(); + anchor = typeExpr; + path = path.slice(1); + continue; + } + LLVM_FALLTHROUGH; + + case ConstraintLocator::Member: + case ConstraintLocator::MemberRefBase: + if (auto UDE = dyn_cast(anchor)) { + range = UDE->getNameLoc().getSourceRange(); + anchor = UDE->getBase(); + path = path.slice(1); + continue; + } + break; + + case ConstraintLocator::SubscriptMember: + if (isa(anchor)) { + path = path.slice(1); + continue; + } + break; + + case ConstraintLocator::ClosureResult: + if (auto CE = dyn_cast(anchor)) { + if (CE->hasSingleExpressionBody()) { + anchor = CE->getSingleExpressionBody(); + path = path.slice(1); + continue; + } + } + break; + + case ConstraintLocator::ContextualType: + // This was just for identifying purposes, strip it off. + path = path.slice(1); + continue; + + default: + // FIXME: Lots of other cases to handle. + break; + } + + // If we get here, we couldn't simplify the path further. + break; + } +} + Expr *constraints::simplifyLocatorToAnchor(ConstraintLocator *locator) { if (!locator) return nullptr; From 26dab57eddb7574cdbe196266912fcc1403a25cc Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Sun, 15 Sep 2019 17:59:26 +0100 Subject: [PATCH 017/199] [CS] NFC: Inline recomputeSummaryFlags --- lib/Sema/ConstraintSystem.cpp | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 3ad8183ea55cb..ed3e0dafa2765 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -2731,14 +2731,6 @@ bool ConstraintSystem::diagnoseAmbiguity(Expr *expr, return false; } -/// Given a subpath of an old locator, compute its summary flags. -static unsigned recomputeSummaryFlags(ConstraintLocator *oldLocator, - ArrayRef path) { - if (oldLocator->getSummaryFlags() != 0) - return ConstraintLocator::getSummaryFlagsForPath(path); - return 0; -} - ConstraintLocator * constraints::simplifyLocator(ConstraintSystem &cs, ConstraintLocator *locator, SourceRange &range) { @@ -2752,10 +2744,12 @@ constraints::simplifyLocator(ConstraintSystem &cs, ConstraintLocator *locator, return locator; } - // Recompute the summary flags if we had any to begin with. This is - // necessary because we might remove e.g. tuple elements from the path. - unsigned summaryFlags = recomputeSummaryFlags(locator, path); - return cs.getConstraintLocator(anchor, path, summaryFlags); + // If the old locator didn't have any summary flags, neither will the + // simplified version, as it must contain a subset of the path elements. + if (locator->getSummaryFlags() == 0) + return cs.getConstraintLocator(anchor, path, /*summaryFlags*/ 0); + + return cs.getConstraintLocator(anchor, path); } void constraints::simplifyLocator(Expr *&anchor, From 176969ddde9fc8b307a32678eebce9ab090a0e54 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Sun, 15 Sep 2019 18:00:15 +0100 Subject: [PATCH 018/199] [CS] Allow simplification of key path subscript arg locators This allows a few fixes to properly emit diagnostics for key path subscript argument contextual failures. Resolves SR-11476. --- lib/Sema/CSDiagnostics.cpp | 6 ++++-- lib/Sema/ConstraintSystem.cpp | 20 ++++++++++++++++++++ test/Constraints/fixes.swift | 15 +++++++++++++++ test/decl/var/property_wrappers.swift | 18 ++++++++++++++++++ 4 files changed, 57 insertions(+), 2 deletions(-) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index c65bdd4e4a8ea..09ebead5a3757 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -1950,8 +1950,10 @@ bool ContextualFailure::diagnoseConversionToNil() const { } // `nil` is passed as an argument to a parameter which doesn't - // expect it e.g. `foo(a: nil)` or `s[x: nil]`. - if (isa(enclosingExpr) || isa(enclosingExpr)) + // expect it e.g. `foo(a: nil)` or `s[x: nil]` or \S.[x: nil]. + // FIXME: Find a more robust way of checking this. + if (isa(enclosingExpr) || isa(enclosingExpr) || + isa(enclosingExpr)) CTP = CTP_CallArgument; } else if (auto *CE = dyn_cast(parentExpr)) { // `nil` is passed as a left-hand side of the coercion diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index ed3e0dafa2765..4442d7f4f4758 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -2911,6 +2911,26 @@ void constraints::simplifyLocator(Expr *&anchor, path = path.slice(1); continue; + case ConstraintLocator::KeyPathComponent: { + auto elt = path[0].castTo(); + + // If the next element is an ApplyArgument, we can simplify by looking + // into the index expression. + if (path.size() < 2 || + path[1].getKind() != ConstraintLocator::ApplyArgument) + break; + + if (auto *kpe = dyn_cast(anchor)) { + auto component = kpe->getComponents()[elt.getIndex()]; + auto indexExpr = component.getIndexExpr(); + assert(indexExpr && "Trying to apply a component without an index?"); + anchor = indexExpr; + path = path.slice(2); + continue; + } + break; + } + default: // FIXME: Lots of other cases to handle. break; diff --git a/test/Constraints/fixes.swift b/test/Constraints/fixes.swift index fd114c918a0a5..028977eeafde7 100644 --- a/test/Constraints/fixes.swift +++ b/test/Constraints/fixes.swift @@ -321,3 +321,18 @@ func test_explicit_call_with_overloads() { foo(S().foo) // expected-error@-1 {{function produces expected type 'Int'; did you mean to call it with '()'?}} {{14-14=()}} } + +// SR-11476 +func testKeyPathSubscriptArgFixes(_ fn: @escaping () -> Int) { + struct S { + subscript(x: Int) -> Int { x } + } + + var i: Int? + _ = \S.[i] // expected-error {{value of optional type 'Int?' must be unwrapped to a value of type 'Int'}} + // expected-note@-1{{coalesce using '??' to provide a default when the optional value contains 'nil'}}{{12-12= ?? <#default value#>}} + // expected-note@-2{{force-unwrap using '!' to abort execution if the optional value contains 'nil'}}{{12-12=!}} + + _ = \S.[nil] // expected-error {{'nil' is not compatible with expected argument type 'Int'}} + _ = \S.[fn] // expected-error {{function produces expected type 'Int'; did you mean to call it with '()'?}} {{13-13=()}} +} diff --git a/test/decl/var/property_wrappers.swift b/test/decl/var/property_wrappers.swift index bce415163d7b9..c277c64354d63 100644 --- a/test/decl/var/property_wrappers.swift +++ b/test/decl/var/property_wrappers.swift @@ -1011,6 +1011,18 @@ struct Foo { // expected-note {{arguments to generic parameter 'T' ('W' and ' } } +extension Foo : Equatable where T : Equatable { + static func == (lhs: Foo, rhs: Foo) -> Bool { + lhs.wrappedValue == rhs.wrappedValue + } +} + +extension Foo : Hashable where T : Hashable { + func hash(into hasher: inout Hasher) { + hasher.combine(wrappedValue) + } +} + @propertyWrapper struct Bar { var wrappedValue: T @@ -1059,6 +1071,8 @@ struct MissingPropertyWrapperUnwrap { func d(_: W) {} func e(_: Foo) {} + subscript(takesFoo x: Foo) -> Foo { x } + func baz() { self.x.foo() // expected-error {{referencing instance method 'foo()' requires wrapper 'Foo'}}{{10-10=_}} self.x.prop // expected-error {{referencing property 'prop' requires wrapper 'Foo'}} {{10-10=_}} @@ -1092,6 +1106,10 @@ struct MissingPropertyWrapperUnwrap { self.x[q: "ultimate question", 42] // expected-error {{referencing subscript 'subscript(q:_:)' requires wrapper 'Foo'}} {{10-10=_}} self.x[q: "ultimate question", 42] = true // expected-error {{referencing subscript 'subscript(q:_:)' requires wrapper 'Foo'}} {{10-10=_}} + + // SR-11476 + _ = \Self.[takesFoo: self.x] // expected-error {{cannot convert value 'x' of type 'Int' to expected type 'Foo', use wrapper instead}}{{31-31=_}} + _ = \Foo.[x: self._x] // expected-error {{cannot convert value '_x' of type 'Foo' to expected type 'Int', use wrapped value instead}} {{26-27=}} } } From 09431763fe27fab40a216c85e27cf2d76359080a Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Sun, 15 Sep 2019 22:00:28 +0100 Subject: [PATCH 019/199] Fix comment --- lib/Sema/CSDiagnostics.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 09ebead5a3757..f2cd523bec460 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -1950,7 +1950,7 @@ bool ContextualFailure::diagnoseConversionToNil() const { } // `nil` is passed as an argument to a parameter which doesn't - // expect it e.g. `foo(a: nil)` or `s[x: nil]` or \S.[x: nil]. + // expect it e.g. `foo(a: nil)`, `s[x: nil]` or `\S.[x: nil]`. // FIXME: Find a more robust way of checking this. if (isa(enclosingExpr) || isa(enclosingExpr) || isa(enclosingExpr)) From efaf1fbefa7fc94ff535b35b964689735637458b Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Mon, 16 Sep 2019 09:20:49 -0700 Subject: [PATCH 020/199] runtime: add a workaround for Windows build The runtime tests will statically link the runtime and dynamically link to the standard library. This fails to build on Windows. This is a horrible workaround for the time being. --- stdlib/public/runtime/MetadataLookup.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp index bc307b6ce15e5..76f52aeb175d0 100644 --- a/stdlib/public/runtime/MetadataLookup.cpp +++ b/stdlib/public/runtime/MetadataLookup.cpp @@ -730,8 +730,14 @@ _findContextDescriptorInCache(TypeMetadataPrivateState &T, $sS ## CHAR ## SUFFIX #define DESCRIPTOR_MANGLING(CHAR, SUFFIX) DESCRIPTOR_MANGLING_(CHAR, SUFFIX) +#if defined(_WIN32) +#define swiftCore_EXPORTS __declspec(dllimport) +#else +#define swiftCore_EXPORTS +#endif + #define STANDARD_TYPE(KIND, MANGLING, TYPENAME) \ - extern "C" const ContextDescriptor DESCRIPTOR_MANGLING(MANGLING, DESCRIPTOR_MANGLING_SUFFIX(KIND)); + extern "C" swiftCore_EXPORTS const ContextDescriptor DESCRIPTOR_MANGLING(MANGLING, DESCRIPTOR_MANGLING_SUFFIX(KIND)); #if !SWIFT_OBJC_INTEROP # define OBJC_INTEROP_STANDARD_TYPE(KIND, MANGLING, TYPENAME) From bb4df032e70279eff1c736a3f528988f35fc8a8c Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Wed, 11 Sep 2019 14:49:17 -0700 Subject: [PATCH 021/199] [ownership] Add a new class BorrowScopeIntroducingValue that enables code to work abstractly with values that introduce a new borrow scope. The idea is that this can be used to work with things like load_borrow, begin_borrow, SILFunctionArgument, results of begin_apply(in the future) and the like in a generic way using exhaustive switches to make sure this code stays up to date. I refactored code in SemanticARCOpts and some utilities in OwnershipUtils.cpp to use these new APIs. The code looks a lot nicer and should be quite easy to expand to handle new borrow introducers (e.x.: end_apply). --- include/swift/SIL/OwnershipUtils.h | 149 +++++++++++++++++- lib/SIL/OwnershipUtils.cpp | 122 +++++++++++--- .../Mandatory/SemanticARCOpts.cpp | 88 ++++------- 3 files changed, 283 insertions(+), 76 deletions(-) diff --git a/include/swift/SIL/OwnershipUtils.h b/include/swift/SIL/OwnershipUtils.h index 4d8a8ec66cd19..55a8fcb8e5e2f 100644 --- a/include/swift/SIL/OwnershipUtils.h +++ b/include/swift/SIL/OwnershipUtils.h @@ -14,6 +14,7 @@ #define SWIFT_SIL_OWNERSHIPUTILS_H #include "swift/Basic/LLVM.h" +#include "swift/SIL/BranchPropagatedUser.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILValue.h" @@ -164,10 +165,152 @@ bool isOwnershipForwardingInst(SILInstruction *i); bool isGuaranteedForwardingInst(SILInstruction *i); +struct BorrowScopeIntroducerKind { + using UnderlyingKindTy = std::underlying_type::type; + + /// Enum we use for exhaustive pattern matching over borrow scope introducers. + enum Kind : UnderlyingKindTy { + LoadBorrow = UnderlyingKindTy(ValueKind::LoadBorrowInst), + BeginBorrow = UnderlyingKindTy(ValueKind::BeginBorrowInst), + SILFunctionArgument = UnderlyingKindTy(ValueKind::SILFunctionArgument), + }; + + static Optional get(ValueKind kind) { + switch (kind) { + default: + return None; + case ValueKind::LoadBorrowInst: + return BorrowScopeIntroducerKind(LoadBorrow); + case ValueKind::BeginBorrowInst: + return BorrowScopeIntroducerKind(BeginBorrow); + case ValueKind::SILFunctionArgument: + return BorrowScopeIntroducerKind(SILFunctionArgument); + } + } + + Kind value; + + BorrowScopeIntroducerKind(Kind newValue) : value(newValue) {} + BorrowScopeIntroducerKind(const BorrowScopeIntroducerKind &other) + : value(other.value) {} + operator Kind() const { return value; } + + /// Is this a borrow scope that begins and ends within the same function and + /// thus is guaranteed to have an "end_scope" instruction. + /// + /// In contrast, borrow scopes that are non-local (e.x. from + /// SILFunctionArguments) rely a construct like a SILFunction as the begin/end + /// of the scope. + bool isLocalScope() const { + switch (value) { + case BorrowScopeIntroducerKind::BeginBorrow: + case BorrowScopeIntroducerKind::LoadBorrow: + return true; + case BorrowScopeIntroducerKind::SILFunctionArgument: + return false; + } + llvm_unreachable("Covered switch isnt covered?!"); + } + + void print(llvm::raw_ostream &os) const; + LLVM_ATTRIBUTE_DEPRECATED(void dump() const, "only for use in the debugger"); +}; + +llvm::raw_ostream &operator<<(llvm::raw_ostream &os, + BorrowScopeIntroducerKind kind); + +/// A higher level construct for working with values that represent the +/// introduction of a new borrow scope. +/// +/// DISCUSSION: A "borrow introducer" is a SILValue that represents the +/// beginning of a borrow scope that the ownership verifier validates. The idea +/// is this API allows one to work in a generic way with all of the various +/// introducers. +/// +/// Some examples of borrow introducers: guaranteed SILFunctionArgument, +/// LoadBorrow, BeginBorrow, guaranteed BeginApply results. +/// +/// NOTE: It is assumed that if a borrow introducer is a value of a +/// SILInstruction with multiple results, that the all of the SILInstruction's +/// guaranteed results are borrow introducers. In practice this means that +/// borrow introducers can not have guaranteed results that are not creating a +/// new borrow scope. No such instructions exist today. +struct BorrowScopeIntroducingValue { + BorrowScopeIntroducerKind kind; + SILValue value; + + BorrowScopeIntroducingValue(LoadBorrowInst *lbi) + : kind(BorrowScopeIntroducerKind::LoadBorrow), value(lbi) {} + BorrowScopeIntroducingValue(BeginBorrowInst *bbi) + : kind(BorrowScopeIntroducerKind::BeginBorrow), value(bbi) {} + BorrowScopeIntroducingValue(SILFunctionArgument *arg) + : kind(BorrowScopeIntroducerKind::SILFunctionArgument), value(arg) { + assert(arg->getOwnershipKind() == ValueOwnershipKind::Guaranteed); + } + + BorrowScopeIntroducingValue(SILValue v) + : kind(*BorrowScopeIntroducerKind::get(v->getKind())), value(v) { + assert(v.getOwnershipKind() == ValueOwnershipKind::Guaranteed); + } + + /// If value is a borrow introducer return it after doing some checks. + static Optional get(SILValue value) { + auto kind = BorrowScopeIntroducerKind::get(value->getKind()); + if (!kind || value.getOwnershipKind() != ValueOwnershipKind::Guaranteed) + return None; + return BorrowScopeIntroducingValue(*kind, value); + } + + /// If this value is introducing a local scope, gather all local end scope + /// instructions and append them to \p scopeEndingInsts. Asserts if this is + /// called with a scope that is not local. + /// + /// NOTE: To determine if a scope is a local scope, call + /// BorrowScopeIntoducingValue::isLocalScope(). + void getLocalScopeEndingInstructions( + SmallVectorImpl &scopeEndingInsts) const; + + /// If this value is introducing a local scope, gather all local end scope + /// instructions and pass them individually to visitor. Asserts if this is + /// called with a scope that is not local. + /// + /// The intention is that this method can be used instead of + /// BorrowScopeIntroducingValue::getLocalScopeEndingInstructions() to avoid + /// introducing an intermediate array when one needs to transform the + /// instructions before storing them. + /// + /// NOTE: To determine if a scope is a local scope, call + /// BorrowScopeIntoducingValue::isLocalScope(). + void visitLocalScopeEndingInstructions( + function_ref visitor) const; + + bool isLocalScope() const { return kind.isLocalScope(); } + + /// Returns true if the passed in set of instructions is completely within the + /// lifetime of this borrow introducer. + /// + /// NOTE: Scratch space is used internally to this method to store the end + /// borrow scopes if needed. + bool areInstructionsWithinScope( + ArrayRef instructions, + SmallVectorImpl &scratchSpace, + SmallPtrSetImpl &visitedBlocks, + DeadEndBlocks &deadEndBlocks) const; + +private: + /// Internal constructor for failable static constructor. Please do not expand + /// its usage since it assumes the code passed in is well formed. + BorrowScopeIntroducingValue(BorrowScopeIntroducerKind kind, SILValue value) + : kind(kind), value(value) {} +}; + /// Look up through the def-use chain of \p inputValue, recording any "borrow" -/// introducers that we find into \p out. -bool getUnderlyingBorrowIntroducers(SILValue inputValue, - SmallVectorImpl &out); +/// introducing values that we find into \p out. If at any point, we find a +/// point in the chain we do not understand, we bail and return false. If we are +/// able to understand all of the def-use graph, we know that we have found all +/// of the borrow introducing values, we return true. +bool getUnderlyingBorrowIntroducingValues( + SILValue inputValue, SmallVectorImpl &out); } // namespace swift diff --git a/lib/SIL/OwnershipUtils.cpp b/lib/SIL/OwnershipUtils.cpp index 516cfa7977f05..3ba913bf3c28f 100644 --- a/lib/SIL/OwnershipUtils.cpp +++ b/lib/SIL/OwnershipUtils.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "swift/SIL/OwnershipUtils.h" +#include "swift/Basic/Defer.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILInstruction.h" @@ -76,8 +77,72 @@ bool swift::isOwnershipForwardingInst(SILInstruction *i) { return isOwnershipForwardingValueKind(SILNodeKind(i->getKind())); } -bool swift::getUnderlyingBorrowIntroducers(SILValue inputValue, - SmallVectorImpl &out) { +//===----------------------------------------------------------------------===// +// Borrow Introducers +//===----------------------------------------------------------------------===// + +void BorrowScopeIntroducerKind::print(llvm::raw_ostream &os) const { + switch (value) { + case BorrowScopeIntroducerKind::SILFunctionArgument: + os << "SILFunctionArgument"; + return; + case BorrowScopeIntroducerKind::BeginBorrow: + os << "BeginBorrowInst"; + return; + case BorrowScopeIntroducerKind::LoadBorrow: + os << "LoadBorrowInst"; + return; + } + llvm_unreachable("Covered switch isn't covered?!"); +} + +void BorrowScopeIntroducerKind::dump() const { +#ifndef NDEBUG + print(llvm::dbgs()); +#endif +} + +void BorrowScopeIntroducingValue::getLocalScopeEndingInstructions( + SmallVectorImpl &scopeEndingInsts) const { + assert(isLocalScope() && "Should only call this given a local scope"); + + switch (kind) { + case BorrowScopeIntroducerKind::SILFunctionArgument: + llvm_unreachable("Should only call this with a local scope"); + case BorrowScopeIntroducerKind::BeginBorrow: + llvm::copy(cast(value)->getEndBorrows(), + std::back_inserter(scopeEndingInsts)); + return; + case BorrowScopeIntroducerKind::LoadBorrow: + llvm::copy(cast(value)->getEndBorrows(), + std::back_inserter(scopeEndingInsts)); + return; + } + llvm_unreachable("Covered switch isn't covered?!"); +} + +void BorrowScopeIntroducingValue::visitLocalScopeEndingInstructions( + function_ref visitor) const { + assert(isLocalScope() && "Should only call this given a local scope"); + switch (kind) { + case BorrowScopeIntroducerKind::SILFunctionArgument: + llvm_unreachable("Should only call this with a local scope"); + case BorrowScopeIntroducerKind::BeginBorrow: + for (auto *inst : cast(value)->getEndBorrows()) { + visitor(inst); + } + return; + case BorrowScopeIntroducerKind::LoadBorrow: + for (auto *inst : cast(value)->getEndBorrows()) { + visitor(inst); + } + return; + } + llvm_unreachable("Covered switch isn't covered?!"); +} + +bool swift::getUnderlyingBorrowIntroducingValues( + SILValue inputValue, SmallVectorImpl &out) { if (inputValue.getOwnershipKind() != ValueOwnershipKind::Guaranteed) return false; @@ -88,25 +153,11 @@ bool swift::getUnderlyingBorrowIntroducers(SILValue inputValue, SILValue v = worklist.pop_back_val(); // First check if v is an introducer. If so, stash it and continue. - if (isa(v) || - isa(v)) { - out.push_back(v); + if (auto scopeIntroducer = BorrowScopeIntroducingValue::get(v)) { + out.push_back(*scopeIntroducer); continue; } - // If we have a function argument with guaranteed convention, it is also an - // introducer. - if (auto *arg = dyn_cast(v)) { - if (arg->getOwnershipKind() == ValueOwnershipKind::Guaranteed) { - out.push_back(v); - continue; - } - - // Otherwise, we do not know how to handle this function argument, so - // bail. - return false; - } - // Otherwise if v is an ownership forwarding value, add its defining // instruction if (isGuaranteedForwardingValue(v)) { @@ -125,3 +176,38 @@ bool swift::getUnderlyingBorrowIntroducers(SILValue inputValue, return true; } + +llvm::raw_ostream &swift::operator<<(llvm::raw_ostream &os, + BorrowScopeIntroducerKind kind) { + kind.print(os); + return os; +} + +bool BorrowScopeIntroducingValue::areInstructionsWithinScope( + ArrayRef instructions, + SmallVectorImpl &scratchSpace, + SmallPtrSetImpl &visitedBlocks, + DeadEndBlocks &deadEndBlocks) const { + // Make sure that we clear our scratch space/utilities before we exit. + SWIFT_DEFER { + scratchSpace.clear(); + visitedBlocks.clear(); + }; + + // First make sure that we actually have a local scope. If we have a non-local + // scope, then we have something (like a SILFunctionArgument) where a larger + // semantic construct (in the case of SILFunctionArgument, the function + // itself) acts as the scope. So we already know that our passed in + // instructions must be in the same scope. + if (!isLocalScope()) + return true; + + // Otherwise, gather up our local scope ending instructions. + visitLocalScopeEndingInstructions( + [&scratchSpace](SILInstruction *i) { scratchSpace.emplace_back(i); }); + + auto result = valueHasLinearLifetime( + value, scratchSpace, instructions, visitedBlocks, deadEndBlocks, + ownership::ErrorBehaviorKind::ReturnFalse); + return !result.getFoundError(); +} diff --git a/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp b/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp index 6b363b9bf44dd..7de95d5579d04 100644 --- a/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp +++ b/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp @@ -299,18 +299,6 @@ bool SemanticARCOptVisitor::visitBeginBorrowInst(BeginBorrowInst *bbi) { return true; } -static bool canHandleOperand(SILValue operand, SmallVectorImpl &out) { - if (!getUnderlyingBorrowIntroducers(operand, out)) - return false; - - /// TODO: Add support for begin_borrow, load_borrow. - auto canHandleValue = [](SILValue v) -> bool { - return isa(v) || isa(v) || - isa(v); - }; - return all_of(out, canHandleValue); -} - // Eliminate a copy of a borrowed value, if: // // 1. All of the copies users do not consume the copy (and thus can accept a @@ -344,11 +332,13 @@ static bool canHandleOperand(SILValue operand, SmallVectorImpl &out) { // // TODO: This needs a better name. bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst *cvi) { - SmallVector borrowIntroducers; + SmallVector borrowScopeIntroducers; - // Whitelist the operands that we know how to support and make sure - // our operand is actually guaranteed. - if (!canHandleOperand(cvi->getOperand(), borrowIntroducers)) + // Find all borrow introducers for our copy operand. If we are unable to find + // all of the reproducers (due to pattern matching failure), conservatively + // return false. We can not optimize. + if (!getUnderlyingBorrowIntroducingValues(cvi->getOperand(), + borrowScopeIntroducers)) return false; // Then go over all of our uses and see if the value returned by our copy @@ -361,10 +351,13 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst if (!isDeadLiveRange(cvi, destroys, &guaranteedForwardingInsts)) return false; - // Next check if we have any destroys at all of our copy_value and an operand - // that is not a function argument. Otherwise, due to the way we ignore dead - // end blocks, we may eliminate the copy_value, creating a use of the borrowed - // value after the end_borrow. + // Next check if we do not have any destroys of our copy_value and are + // processing a local borrow scope. In such a case, due to the way we ignore + // dead end blocks, we may eliminate the copy_value, creating a use of the + // borrowed value after the end_borrow. To avoid this, in such cases we + // bail. In contrast, a non-local borrow scope does not have any end scope + // instructions, implying we can avoid this hazard and still optimize in such + // a case. // // DISCUSSION: Consider the following SIL: // @@ -411,48 +404,33 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst // destroy_value /after/ the end_borrow we will not optimize here. This means // that this bug can only occur if the copy_value is only post-dominated by // dead end blocks that use the value in a non-consuming way. - if (destroys.empty() && llvm::any_of(borrowIntroducers, [](SILValue v) { - return !isa(v); - })) { + // + // TODO: There may be some way of sinking this into the loop below. + if (destroys.empty() && + llvm::any_of(borrowScopeIntroducers, + [](BorrowScopeIntroducingValue borrowScope) { + return borrowScope.isLocalScope(); + })) { return false; } - // If we reached this point, then we know that all of our users can - // accept a guaranteed value and our owned value is destroyed only - // by destroy_value. Check if all of our destroys are joint - // post-dominated by the end_borrow set. If they do not, then the - // copy_value is lifetime extending the guaranteed value, we can not - // eliminate it. + // If we reached this point, then we know that all of our users can accept a + // guaranteed value and our owned value is destroyed only by + // destroy_value. Check if all of our destroys are joint post-dominated by the + // our end borrow scope set. If they do not, then the copy_value is lifetime + // extending the guaranteed value, we can not eliminate it. { SmallVector destroysForLinearLifetimeCheck( destroys.begin(), destroys.end()); - SmallVector endBorrowInsts; + SmallVector scratchSpace; SmallPtrSet visitedBlocks; - for (SILValue v : borrowIntroducers) { - if (isa(v)) { - continue; - } - - SWIFT_DEFER { - endBorrowInsts.clear(); - visitedBlocks.clear(); - }; - - if (auto *lbi = dyn_cast(v)) { - llvm::copy(lbi->getEndBorrows(), std::back_inserter(endBorrowInsts)); - } else if (auto *bbi = dyn_cast(v)) { - llvm::copy(bbi->getEndBorrows(), std::back_inserter(endBorrowInsts)); - } else { - llvm_unreachable("Unhandled borrow introducer?!"); - } - - // Make sure that our destroys are properly nested within our end - // borrows. Otherwise, we can not optimize. - auto result = valueHasLinearLifetime( - v, endBorrowInsts, destroysForLinearLifetimeCheck, visitedBlocks, - getDeadEndBlocks(), ownership::ErrorBehaviorKind::ReturnFalse); - if (result.getFoundError()) - return false; + if (llvm::any_of(borrowScopeIntroducers, + [&](BorrowScopeIntroducingValue borrowScope) { + return !borrowScope.areInstructionsWithinScope( + destroysForLinearLifetimeCheck, scratchSpace, + visitedBlocks, getDeadEndBlocks()); + })) { + return false; } } From 907c2eb99ba6d5f4003250f0f9377d3ed4b633e2 Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Mon, 16 Sep 2019 19:34:38 +0100 Subject: [PATCH 022/199] [Typechecker] When creating the pattern binding for the backing variable, use the original property's static spelling --- lib/Sema/TypeCheckStorage.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index afacf13a03a87..9208a5a8331a5 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -2348,8 +2348,8 @@ PropertyWrapperBackingPropertyInfoRequest::evaluate(Evaluator &evaluator, pbdPattern->setType(storageType); pbdPattern = TypedPattern::createImplicit(ctx, pbdPattern, storageType); auto pbd = PatternBindingDecl::createImplicit( - ctx, backingVar->getCorrectStaticSpelling(), pbdPattern, - /*init*/nullptr, dc, SourceLoc()); + ctx, var->getCorrectStaticSpelling(), pbdPattern, + /*init*/ nullptr, dc, SourceLoc()); addMemberToContextIfNeeded(pbd, dc, var); pbd->setStatic(var->isStatic()); From d097c8186d76da1dba7aab1854cf4073dc01b4ab Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 11 Sep 2019 12:53:48 -0700 Subject: [PATCH 023/199] Requestify generic signatures Define a request that provides the generic signature for a given generic context. This unblocks a ton of cleanup and will allow us to remove validateExtension, validateDeclForNameLookup, and a lot of the surrounding infrastructure. Being more honest about which declarations actually have a generic signature computed has naturally introduced more cycles in requests. hasComputedGenericSignature() now acts as a recursion breaker. In the future, we should purge any uses of this accessor that specifically head-off cycles as the cycle itself is probably part of a larger structural problem. --- include/swift/AST/Decl.h | 8 +- include/swift/AST/TypeCheckRequests.h | 21 ++ include/swift/AST/TypeCheckerTypeIDZone.def | 3 + lib/AST/Decl.cpp | 35 +- lib/AST/TypeCheckRequests.cpp | 17 + lib/Sema/TypeCheckDecl.cpp | 232 ++++-------- lib/Sema/TypeCheckGeneric.cpp | 381 +++++++++++--------- lib/Sema/TypeChecker.h | 32 +- 8 files changed, 368 insertions(+), 361 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 4ce8dde68da5f..38e336135ebaf 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -1505,12 +1505,13 @@ class alignas(8) _GenericContext { TrailingWhereClause *TrailingWhere = nullptr; /// The generic signature of this declaration. - GenericSignature *GenericSig = nullptr; + llvm::PointerIntPair GenericSigAndBit; }; class GenericContext : private _GenericContext, public DeclContext { friend class GenericParamListRequest; - + friend class GenericSignatureRequest; + protected: GenericContext(DeclContextKind Kind, DeclContext *Parent, GenericParamList *Params); @@ -1534,7 +1535,8 @@ class GenericContext : private _GenericContext, public DeclContext { /// } /// \endcode bool isGeneric() const { return getGenericParams() != nullptr; } - + bool hasComputedGenericSignature() const; + /// Retrieve the trailing where clause for this extension, if any. TrailingWhereClause *getTrailingWhereClause() const { return TrailingWhere; diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 7e78ded29e668..cf562bd6feb32 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -1160,6 +1160,27 @@ class FunctionOperatorRequest : bool isCached() const { return true; } }; +class GenericSignatureRequest : + public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + llvm::Expected + evaluate(Evaluator &evaluator, GenericContext *value) const; + +public: + // Separate caching. + bool isCached() const { return true; } + Optional getCachedResult() const; + void cacheResult(GenericSignature *value) const; +}; + // Allow AnyValue to compare two Type values, even though Type doesn't // support ==. template<> diff --git a/include/swift/AST/TypeCheckerTypeIDZone.def b/include/swift/AST/TypeCheckerTypeIDZone.def index c600565126102..7d14fbbfd941c 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -49,6 +49,9 @@ SWIFT_REQUEST(TypeChecker, FunctionBuilderTypeRequest, Type(ValueDecl *), Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, FunctionOperatorRequest, OperatorDecl *(FuncDecl *), Cached, NoLocationInfo) +SWIFT_REQUEST(NameLookup, GenericSignatureRequest, + GenericSignature *(GenericContext *), + SeparatelyCached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, InferredGenericSignatureRequest, GenericSignature *(ModuleDecl *, GenericSignature *, SmallVector, diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index d3f5a25b2e607..c570f65f4ccd8 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -855,22 +855,14 @@ GenericParamList *GenericContext::getGenericParams() const { const_cast(this)}, nullptr); } -GenericSignature *GenericContext::getGenericSignature() const { - if (GenericSig) - return GenericSig; - - // The signature of a Protocol is trivial (Self: TheProtocol) so let's compute - // it. - if (auto PD = dyn_cast(this)) { - auto self = PD->getSelfInterfaceType()->castTo(); - auto req = - Requirement(RequirementKind::Conformance, self, PD->getDeclaredType()); - const_cast(this)->GenericSig - = GenericSignature::get({self}, {req}); - return GenericSig; - } +bool GenericContext::hasComputedGenericSignature() const { + return GenericSigAndBit.getInt(); +} - return nullptr; +GenericSignature *GenericContext::getGenericSignature() const { + return evaluateOrDefault( + getASTContext().evaluator, + GenericSignatureRequest{const_cast(this)}, nullptr); } GenericEnvironment *GenericContext::getGenericEnvironment() const { @@ -881,8 +873,9 @@ GenericEnvironment *GenericContext::getGenericEnvironment() const { } void GenericContext::setGenericSignature(GenericSignature *genericSig) { - assert(GenericSig == nullptr && "Generic signature cannot be changed"); - this->GenericSig = genericSig; + assert(!GenericSigAndBit.getPointer() && "Generic signature cannot be changed"); + getASTContext().evaluator.cacheOutput(GenericSignatureRequest{this}, + std::move(genericSig)); } SourceRange GenericContext::getGenericTrailingWhereClauseSourceRange() const { @@ -6159,6 +6152,10 @@ void SubscriptDecl::computeType() { // Record the interface type. setInterfaceType(funcTy); + + // Make sure that there are no unresolved dependent types in the + // generic signature. + assert(!funcTy->findUnresolvedDependentMemberType()); } ObjCSubscriptKind SubscriptDecl::getObjCSubscriptKind() const { @@ -6753,6 +6750,10 @@ void AbstractFunctionDecl::computeType(AnyFunctionType::ExtInfo info) { // Compute the type of the 'self' parameter if we're created one already. if (hasSelf) computeSelfDeclType(); + + // Make sure that there are no unresolved dependent types in the + // generic signature. + assert(!funcTy->findUnresolvedDependentMemberType()); } bool AbstractFunctionDecl::hasInlinableBodyText() const { diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index 5bfbbcbeb5a39..f3814ce7d0b91 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -805,3 +805,20 @@ void IsImplicitlyUnwrappedOptionalRequest::cacheResult(bool value) const { auto *decl = std::get<0>(getStorage()); decl->setImplicitlyUnwrappedOptional(value); } + +//----------------------------------------------------------------------------// +// GenericSignatureRequest computation. +//----------------------------------------------------------------------------// + +Optional GenericSignatureRequest::getCachedResult() const { + auto *GC = std::get<0>(getStorage()); + if (GC->GenericSigAndBit.getInt()) { + return GC->GenericSigAndBit.getPointer(); + } + return None; +} + +void GenericSignatureRequest::cacheResult(GenericSignature *value) const { + auto *GC = std::get<0>(getStorage()); + GC->GenericSigAndBit.setPointerAndInt(value, true); +} diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index ca34b02d43457..125bf63f41aa4 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2416,6 +2416,8 @@ class DeclChecker : public DeclVisitor { void visitSubscriptDecl(SubscriptDecl *SD) { TC.validateDecl(SD); + // Force creation of the generic signature. + (void)SD->getGenericSignature(); if (!SD->isInvalid()) { TC.checkReferencedGenericParams(SD); checkGenericParams(SD->getGenericParams(), SD, TC); @@ -2466,6 +2468,9 @@ class DeclChecker : public DeclVisitor { TC.validateDecl(TAD); TC.checkDeclAttributes(TAD); + // Force the generic signature to be computed in case it emits diagnostics. + (void)TAD->getGenericSignature(); + checkAccessControl(TC, TAD); } @@ -2473,6 +2478,9 @@ class DeclChecker : public DeclVisitor { TC.validateDecl(OTD); TC.checkDeclAttributes(OTD); + // Force the generic signature to be computed in case it emits diagnostics. + (void)OTD->getGenericSignature(); + checkAccessControl(TC, OTD); } @@ -2526,6 +2534,7 @@ class DeclChecker : public DeclVisitor { TC.diagnose(NTD->getLoc(), diag::unsupported_nested_protocol, NTD->getName()); + NTD->setInvalid(); return; } @@ -2721,6 +2730,8 @@ class DeclChecker : public DeclVisitor { checkUnsupportedNestedType(CD); TC.validateDecl(CD); + // Force creation of the generic signature. + (void)CD->getGenericSignature(); checkGenericParams(CD->getGenericParams(), CD, TC); { @@ -3693,6 +3704,27 @@ static Type buildAddressorResultType(TypeChecker &TC, return pointerType; } + +static void validateResultType(TypeChecker &TC, + ValueDecl *decl, ParameterList *params, + TypeLoc &resultTyLoc, + TypeResolution resolution) { + // Nothing to do if there's no result type loc to set into. + if (resultTyLoc.isNull()) + return; + + // Check the result type. It is allowed to be opaque. + if (auto opaqueTy = + dyn_cast_or_null(resultTyLoc.getTypeRepr())) { + // Create the decl and type for it. + resultTyLoc.setType( + TC.getOrCreateOpaqueResultType(resolution, decl, opaqueTy)); + } else { + TC.validateType(resultTyLoc, resolution, + TypeResolverContext::FunctionResult); + } +} + void TypeChecker::validateDecl(ValueDecl *D) { // Generic parameters are validated as part of their context. if (isa(D)) @@ -3782,8 +3814,6 @@ void TypeChecker::validateDecl(ValueDecl *D) { auto typeAlias = cast(D); // Check generic parameters, if needed. DeclValidationRAII IBV(typeAlias); - - validateGenericTypeSignature(typeAlias); validateTypealiasType(*this, typeAlias); break; } @@ -3791,7 +3821,6 @@ void TypeChecker::validateDecl(ValueDecl *D) { case DeclKind::OpaqueType: { auto opaque = cast(D); DeclValidationRAII IBV(opaque); - validateGenericTypeSignature(opaque); break; } @@ -3803,7 +3832,7 @@ void TypeChecker::validateDecl(ValueDecl *D) { // Check generic parameters, if needed. DeclValidationRAII IBV(nominal); - validateGenericTypeSignature(nominal); + (void)nominal->getGenericSignature(); nominal->setSignatureIsValidated(); if (auto *ED = dyn_cast(nominal)) { @@ -3823,7 +3852,7 @@ void TypeChecker::validateDecl(ValueDecl *D) { // Validate the generic type signature, which is just . DeclValidationRAII IBV(proto); - validateGenericTypeSignature(proto); + (void)proto->getGenericSignature(); proto->setSignatureIsValidated(); // See the comment in validateDeclForNameLookup(); we may have validated @@ -3833,10 +3862,10 @@ void TypeChecker::validateDecl(ValueDecl *D) { for (auto member : proto->getMembers()) { if (auto *aliasDecl = dyn_cast(member)) { if (!aliasDecl->isGeneric()) { + assert(aliasDecl->getGenericSignature() == proto->getGenericSignature()); // FIXME: Force creation of the protocol's generic environment now. (void) proto->getGenericEnvironment(); - aliasDecl->setGenericSignature(proto->getGenericSignature()); - + // The generic environment didn't exist until now, we may have // unresolved types we will need to deal with, and need to record the // appropriate substitutions for that environment. Wipe out the types @@ -4026,11 +4055,17 @@ void TypeChecker::validateDecl(ValueDecl *D) { break; } } - - validateGenericFuncOrSubscriptSignature(FD, FD, FD); // We want the function to be available for name lookup as soon // as it has a valid interface type. + auto resolution = TypeResolution::forInterface(FD, + FD->getGenericSignature()); + typeCheckParameterList(FD->getParameters(), resolution, + TypeResolverContext::AbstractFunctionDecl); + validateResultType(*this, FD, FD->getParameters(), + FD->getBodyResultTypeLoc(), resolution); + // FIXME: Roll all of this interface type computation into a request. + FD->computeType(); FD->setSignatureIsValidated(); // Member functions need some special validation logic. @@ -4072,7 +4107,10 @@ void TypeChecker::validateDecl(ValueDecl *D) { DeclValidationRAII IBV(CD); - validateGenericFuncOrSubscriptSignature(CD, CD, CD); + auto res = TypeResolution::forInterface(CD, CD->getGenericSignature()); + typeCheckParameterList(CD->getParameters(), res, + TypeResolverContext::AbstractFunctionDecl); + CD->computeType(); // We want the constructor to be available for name lookup as soon // as it has a valid interface type. @@ -4086,7 +4124,10 @@ void TypeChecker::validateDecl(ValueDecl *D) { DeclValidationRAII IBV(DD); - validateGenericFuncOrSubscriptSignature(DD, DD, DD); + auto res = TypeResolution::forInterface(DD, DD->getGenericSignature()); + typeCheckParameterList(DD->getParameters(), res, + TypeResolverContext::AbstractFunctionDecl); + DD->computeType(); DD->setSignatureIsValidated(); break; @@ -4097,7 +4138,12 @@ void TypeChecker::validateDecl(ValueDecl *D) { DeclValidationRAII IBV(SD); - validateGenericFuncOrSubscriptSignature(SD, SD, SD); + auto res = TypeResolution::forInterface(SD, SD->getGenericSignature()); + typeCheckParameterList(SD->getIndices(), res, + TypeResolverContext::SubscriptDecl); + validateResultType(*this, SD, SD->getIndices(), + SD->getElementTypeLoc(), res); + SD->computeType(); SD->setSignatureIsValidated(); @@ -4282,25 +4328,7 @@ EmittedMembersRequest::evaluate(Evaluator &evaluator, return CD->getMembers(); } -/// Determine whether this is a "pass-through" typealias, which has the -/// same type parameters as the nominal type it references and specializes -/// the underlying nominal type with exactly those type parameters. -/// For example, the following typealias \c GX is a pass-through typealias: -/// -/// \code -/// struct X { } -/// typealias GX = X -/// \endcode -/// -/// whereas \c GX2 and \c GX3 are not pass-through because \c GX2 has -/// different type parameters and \c GX3 doesn't pass its type parameters -/// directly through. -/// -/// \code -/// typealias GX2 = X -/// typealias GX3 = X -/// \endcode -static bool isPassThroughTypealias(TypeAliasDecl *typealias) { +bool TypeChecker::isPassThroughTypealias(TypeAliasDecl *typealias) { // Pass-through only makes sense when the typealias refers to a nominal // type. Type underlyingType = typealias->getUnderlyingTypeLoc().getType(); @@ -4353,135 +4381,6 @@ static bool isPassThroughTypealias(TypeAliasDecl *typealias) { }); } -/// Form the interface type of an extension from the raw type and the -/// extension's list of generic parameters. -static Type formExtensionInterfaceType( - TypeChecker &tc, ExtensionDecl *ext, - Type type, - GenericParamList *genericParams, - SmallVectorImpl &sameTypeReqs, - bool &mustInferRequirements) { - if (type->is()) - return type; - - // Find the nominal type declaration and its parent type. - if (type->is()) - type = type->getCanonicalType(); - - Type parentType = type->getNominalParent(); - GenericTypeDecl *genericDecl = type->getAnyGeneric(); - - // Reconstruct the parent, if there is one. - if (parentType) { - // Build the nested extension type. - auto parentGenericParams = genericDecl->getGenericParams() - ? genericParams->getOuterParameters() - : genericParams; - parentType = - formExtensionInterfaceType(tc, ext, parentType, parentGenericParams, - sameTypeReqs, mustInferRequirements); - } - - // Find the nominal type. - auto nominal = dyn_cast(genericDecl); - auto typealias = dyn_cast(genericDecl); - if (!nominal) { - Type underlyingType = typealias->getUnderlyingTypeLoc().getType(); - nominal = underlyingType->getNominalOrBoundGenericNominal(); - } - - // Form the result. - Type resultType; - SmallVector genericArgs; - if (!nominal->isGeneric() || isa(nominal)) { - resultType = NominalType::get(nominal, parentType, - nominal->getASTContext()); - } else { - auto currentBoundType = type->getAs(); - - // Form the bound generic type with the type parameters provided. - unsigned gpIndex = 0; - for (auto gp : *genericParams) { - SWIFT_DEFER { ++gpIndex; }; - - auto gpType = gp->getDeclaredInterfaceType(); - genericArgs.push_back(gpType); - - if (currentBoundType) { - sameTypeReqs.emplace_back(RequirementKind::SameType, gpType, - currentBoundType->getGenericArgs()[gpIndex]); - } - } - - resultType = BoundGenericType::get(nominal, parentType, genericArgs); - } - - // If we have a typealias, try to form type sugar. - if (typealias && isPassThroughTypealias(typealias)) { - auto typealiasSig = typealias->getGenericSignature(); - SubstitutionMap subMap; - if (typealiasSig) { - subMap = typealiasSig->getIdentitySubstitutionMap(); - - mustInferRequirements = true; - } - - resultType = TypeAliasType::get(typealias, parentType, subMap, - resultType); - } - - return resultType; -} - -/// Retrieve the generic parameter depth of the extended type. -static unsigned getExtendedTypeGenericDepth(ExtensionDecl *ext) { - auto nominal = ext->getSelfNominalTypeDecl(); - if (!nominal) return static_cast(-1); - - auto sig = nominal->getGenericSignatureOfContext(); - if (!sig) return static_cast(-1); - - return sig->getGenericParams().back()->getDepth(); -} - -/// Check the generic parameters of an extension, recursively handling all of -/// the parameter lists within the extension. -static GenericSignature * -checkExtensionGenericParams(TypeChecker &tc, ExtensionDecl *ext, - GenericParamList *genericParams) { - assert(!ext->getGenericEnvironment()); - - // Form the interface type of the extension. - bool mustInferRequirements = false; - SmallVector sameTypeReqs; - Type extInterfaceType = - formExtensionInterfaceType(tc, ext, ext->getExtendedType(), - genericParams, sameTypeReqs, - mustInferRequirements); - - assert(genericParams && "Missing generic parameters?"); - - auto cannotReuseNominalSignature = [&]() -> bool { - const auto finalDepth = genericParams->getParams().back()->getDepth(); - return mustInferRequirements - || !sameTypeReqs.empty() - || ext->getTrailingWhereClause() - || (getExtendedTypeGenericDepth(ext) != finalDepth); - }; - - // Re-use the signature of the type being extended by default. - if (cannotReuseNominalSignature()) { - return TypeChecker::checkGenericSignature( - genericParams, ext, - /*parent signature*/ nullptr, - /*allowConcreteGenericParams=*/true, - sameTypeReqs, - {TypeLoc{nullptr, extInterfaceType}}); - } - - return ext->getSelfNominalTypeDecl()->getGenericSignatureOfContext(); -} - static bool isNonGenericTypeAliasType(Type type) { // A non-generic typealias can extend a specialized type. if (auto *aliasType = dyn_cast(type.getPointer())) @@ -4516,7 +4415,7 @@ ExtendedTypeRequest::evaluate(Evaluator &eval, ExtensionDecl *ext) const { if (auto *aliasDecl = dyn_cast(unboundGeneric->getDecl())) { auto extendedNominal = aliasDecl->getDeclaredInterfaceType()->getAnyNominal(); if (extendedNominal) - return isPassThroughTypealias(aliasDecl) + return TypeChecker::isPassThroughTypealias(aliasDecl) ? extendedType : extendedNominal->getDeclaredType(); } @@ -4562,11 +4461,12 @@ void TypeChecker::validateExtension(ExtensionDecl *ext) { if (auto *nominal = ext->getExtendedNominal()) { // Validate the nominal type declaration being extended. validateDecl(nominal); - - if (auto *genericParams = ext->getGenericParams()) { - auto *sig = checkExtensionGenericParams(*this, ext, genericParams); - ext->setGenericSignature(sig); - } + + // FIXME: validateExtension is going to disappear soon. In the mean time + // don't bother computing the generic signature if the extended nominal type + // didn't pass validation so we don't crash. + if (!nominal->isInvalid()) + (void)ext->getGenericSignature(); } } diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index c4f53ef1e9b8f..e58655319b6a5 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -443,144 +443,6 @@ void TypeChecker::checkReferencedGenericParams(GenericContext *dc) { } } -void TypeChecker::validateGenericFuncOrSubscriptSignature( - PointerUnion - funcOrSubscript, - ValueDecl *decl, GenericContext *genCtx) { - auto func = funcOrSubscript.dyn_cast(); - auto subscr = funcOrSubscript.dyn_cast(); - - auto gpList = genCtx->getGenericParams(); - if (gpList) { - // Do some initial configuration of the generic parameter lists that's - // required in all cases. - gpList->setDepth(genCtx->getGenericContextDepth()); - } else { - // Inherit the signature of the surrounding environment. - genCtx->setGenericSignature( - decl->getDeclContext()->getGenericSignatureOfContext()); - } - - // Accessors can always use the generic context of their storage - // declarations. This is a compile-time optimization since it lets us - // avoid the requirements-gathering phase, but it also simplifies that - // work for accessors which don't mention the value type in their formal - // signatures (like the read and modify coroutines, since yield types - // aren't tracked in the AST type yet). - if (auto accessor = dyn_cast(decl)) { - auto subscr = dyn_cast(accessor->getStorage()); - if (gpList && subscr) { - genCtx->setGenericSignature(subscr->getGenericSignature()); - } - // We've inherited all of the type information already. - accessor->computeType(); - return; - } - - // Use the generic signature of the surrounding context by default. - GenericSignature *sig = - decl->getDeclContext()->getGenericSignatureOfContext(); - - auto params = func ? func->getParameters() : subscr->getIndices(); - TypeLoc emptyLoc; - TypeLoc &resultTyLoc = [&]() -> TypeLoc& { - if (subscr) - return subscr->getElementTypeLoc(); - if (auto fn = dyn_cast(func)) - return fn->getBodyResultTypeLoc(); - return emptyLoc; - }(); - - if (gpList) { - // Gather requirements from the parameter list. - auto resolution = TypeResolution::forStructural(genCtx); - - TypeResolutionOptions options = - (func - ? TypeResolverContext::AbstractFunctionDecl - : TypeResolverContext::SubscriptDecl); - - SmallVector inferenceSources; - for (auto param : *params) { - auto *typeRepr = param->getTypeLoc().getTypeRepr(); - if (typeRepr == nullptr) - continue; - - auto paramOptions = options; - paramOptions.setContext(param->isVariadic() ? - TypeResolverContext::VariadicFunctionInput : - TypeResolverContext::FunctionInput); - paramOptions |= TypeResolutionFlags::Direct; - - auto type = resolution.resolveType(typeRepr, paramOptions); - - if (auto *specifier = dyn_cast_or_null(typeRepr)) - typeRepr = specifier->getBase(); - - inferenceSources.emplace_back(typeRepr, type); - } - - // Gather requirements from the result type. - auto *resultTypeRepr = resultTyLoc.getTypeRepr(); - if (resultTypeRepr && !isa(resultTypeRepr)) { - TypeResolutionOptions resultOptions = TypeResolverContext::FunctionResult; - - auto resultType = resolution.resolveType(resultTypeRepr, resultOptions); - - inferenceSources.emplace_back(resultTypeRepr, resultType); - } - - // The signature is complete and well-formed. Determine - // the type of the generic function or subscript. - auto request = InferredGenericSignatureRequest{ - genCtx->getParentModule(), - decl->getDeclContext() - ->getGenericSignatureOfContext(), - {gpList}, {}, inferenceSources, - /*allowConcreteGenericParams=*/false}; - sig = evaluateOrDefault(Context.evaluator, request, nullptr); - - // Debugging of the generic signature. - if (Context.LangOpts.DebugGenericSignatures) { - decl->dumpRef(llvm::errs()); - llvm::errs() << "\n"; - llvm::errs() << "Generic signature: "; - sig->print(llvm::errs()); - llvm::errs() << "\n"; - llvm::errs() << "Canonical generic signature: "; - sig->getCanonicalSignature()->print(llvm::errs()); - llvm::errs() << "\n"; - } - - genCtx->setGenericSignature(sig); - } - - auto resolution = TypeResolution::forInterface(genCtx, sig); - // Check parameter patterns. - typeCheckParameterList(params, resolution, func - ? TypeResolverContext::AbstractFunctionDecl - : TypeResolverContext::SubscriptDecl); - - if (!resultTyLoc.isNull()) { - // Check the result type. It is allowed to be opaque. - if (auto opaqueTy = dyn_cast_or_null( - resultTyLoc.getTypeRepr())) { - // Create the decl and type for it. - resultTyLoc.setType( - getOrCreateOpaqueResultType(resolution, decl, opaqueTy)); - } else { - validateType(Context, resultTyLoc, resolution, - TypeResolverContext::FunctionResult); - } - } - - func ? func->computeType() : subscr->computeType(); - - // Make sure that there are no unresolved dependent types in the - // generic signature. - assert(!decl->getInterfaceType()->findUnresolvedDependentMemberType()); -} - /// /// Generic types /// @@ -614,7 +476,11 @@ GenericSignature *TypeChecker::checkGenericSignature( // Debugging of the generic signature builder and generic signature // generation. if (dc->getASTContext().LangOpts.DebugGenericSignatures) { - dc->printContext(llvm::errs()); + if (auto *VD = dyn_cast_or_null(dc->getAsDecl())) { + VD->dumpRef(llvm::errs()); + } else { + dc->printContext(llvm::errs()); + } llvm::errs() << "\n"; llvm::errs() << "Generic signature: "; sig->print(llvm::errs()); @@ -627,8 +493,107 @@ GenericSignature *TypeChecker::checkGenericSignature( return sig; } -void TypeChecker::validateGenericTypeSignature(GenericTypeDecl *typeDecl) { - if (auto *proto = dyn_cast(typeDecl)) { +/// Form the interface type of an extension from the raw type and the +/// extension's list of generic parameters. +static Type formExtensionInterfaceType( + ExtensionDecl *ext, Type type, + GenericParamList *genericParams, + SmallVectorImpl &sameTypeReqs, + bool &mustInferRequirements) { + if (type->is()) + return type; + + // Find the nominal type declaration and its parent type. + if (type->is()) + type = type->getCanonicalType(); + + Type parentType = type->getNominalParent(); + GenericTypeDecl *genericDecl = type->getAnyGeneric(); + + // Reconstruct the parent, if there is one. + if (parentType) { + // Build the nested extension type. + auto parentGenericParams = genericDecl->getGenericParams() + ? genericParams->getOuterParameters() + : genericParams; + parentType = + formExtensionInterfaceType(ext, parentType, parentGenericParams, + sameTypeReqs, mustInferRequirements); + } + + // Find the nominal type. + auto nominal = dyn_cast(genericDecl); + auto typealias = dyn_cast(genericDecl); + if (!nominal) { + Type underlyingType = typealias->getUnderlyingTypeLoc().getType(); + nominal = underlyingType->getNominalOrBoundGenericNominal(); + } + + // Form the result. + Type resultType; + SmallVector genericArgs; + if (!nominal->isGeneric() || isa(nominal)) { + resultType = NominalType::get(nominal, parentType, + nominal->getASTContext()); + } else { + auto currentBoundType = type->getAs(); + + // Form the bound generic type with the type parameters provided. + unsigned gpIndex = 0; + for (auto gp : *genericParams) { + SWIFT_DEFER { ++gpIndex; }; + + auto gpType = gp->getDeclaredInterfaceType(); + genericArgs.push_back(gpType); + + if (currentBoundType) { + sameTypeReqs.emplace_back(RequirementKind::SameType, gpType, + currentBoundType->getGenericArgs()[gpIndex]); + } + } + + resultType = BoundGenericType::get(nominal, parentType, genericArgs); + } + + // If we have a typealias, try to form type sugar. + if (typealias && TypeChecker::isPassThroughTypealias(typealias)) { + auto typealiasSig = typealias->getGenericSignature(); + SubstitutionMap subMap; + if (typealiasSig) { + subMap = typealiasSig->getIdentitySubstitutionMap(); + + mustInferRequirements = true; + } + + resultType = TypeAliasType::get(typealias, parentType, subMap, + resultType); + } + + return resultType; +} + +/// Retrieve the generic parameter depth of the extended type. +static unsigned getExtendedTypeGenericDepth(ExtensionDecl *ext) { + auto nominal = ext->getSelfNominalTypeDecl(); + if (!nominal) return static_cast(-1); + + auto sig = nominal->getGenericSignatureOfContext(); + if (!sig) return static_cast(-1); + + return sig->getGenericParams().back()->getDepth(); +} + +llvm::Expected +GenericSignatureRequest::evaluate(Evaluator &evaluator, + GenericContext *GC) const { + // The signature of a Protocol is trivial (Self: TheProtocol) so let's compute + // it. + if (auto PD = dyn_cast(GC)) { + auto self = PD->getSelfInterfaceType()->castTo(); + auto req = + Requirement(RequirementKind::Conformance, self, PD->getDeclaredType()); + auto *sig = GenericSignature::get({self}, {req}); + // The requirement signature is created lazily by // ProtocolDecl::getRequirementSignature(). // The generic signature and environment is created lazily by @@ -637,10 +602,8 @@ void TypeChecker::validateGenericTypeSignature(GenericTypeDecl *typeDecl) { // Debugging of the generic signature builder and generic signature // generation. - if (Context.LangOpts.DebugGenericSignatures) { - auto *sig = proto->getGenericSignature(); - - proto->printContext(llvm::errs()); + if (GC->getASTContext().LangOpts.DebugGenericSignatures) { + PD->printContext(llvm::errs()); llvm::errs() << "\n"; llvm::errs() << "Generic signature: "; sig->print(llvm::errs()); @@ -649,32 +612,124 @@ void TypeChecker::validateGenericTypeSignature(GenericTypeDecl *typeDecl) { sig->getCanonicalSignature()->print(llvm::errs()); llvm::errs() << "\n"; } + return sig; + } - return; + // We can fast-path computing the generic signature of non-generic + // declarations by re-using the parent context's signature. + auto *gp = GC->getGenericParams(); + if (!gp) { + return GC->getParent()->getGenericSignatureOfContext(); } - assert(!typeDecl->getGenericEnvironment()); + // Setup the depth of the generic parameters. + gp->setDepth(GC->getGenericContextDepth()); - // We don't go down this path for protocols; instead, the generic signature - // is simple enough that GenericContext::getGenericSignature() can build it - // directly. - assert(!isa(typeDecl)); + // Accessors can always use the generic context of their storage + // declarations. This is a compile-time optimization since it lets us + // avoid the requirements-gathering phase, but it also simplifies that + // work for accessors which don't mention the value type in their formal + // signatures (like the read and modify coroutines, since yield types + // aren't tracked in the AST type yet). + if (auto accessor = dyn_cast(GC->getAsDecl())) { + return cast(accessor->getStorage())->getGenericSignature(); + } + + bool allowConcreteGenericParams = false; + SmallVector inferenceSources; + SmallVector sameTypeReqs; + if (auto VD = dyn_cast_or_null(GC->getAsDecl())) { + auto func = dyn_cast(VD); + auto subscr = dyn_cast(VD); + + // For functions and subscripts, resolve the parameter and result types and + // note them as inference sources. + if (subscr || func) { + // Gather requirements from the parameter list. + auto resolution = TypeResolution::forStructural(GC); + + TypeResolutionOptions options = + (func ? TypeResolverContext::AbstractFunctionDecl + : TypeResolverContext::SubscriptDecl); + + auto params = func ? func->getParameters() : subscr->getIndices(); + for (auto param : *params) { + auto *typeRepr = param->getTypeLoc().getTypeRepr(); + if (typeRepr == nullptr) + continue; - auto *gp = typeDecl->getGenericParams(); - auto *dc = typeDecl->getDeclContext(); + auto paramOptions = options; + paramOptions.setContext(param->isVariadic() + ? TypeResolverContext::VariadicFunctionInput + : TypeResolverContext::FunctionInput); + paramOptions |= TypeResolutionFlags::Direct; - if (!gp) { - typeDecl->setGenericSignature(dc->getGenericSignatureOfContext()); - return; - } + auto type = resolution.resolveType(typeRepr, paramOptions); + + if (auto *specifier = dyn_cast(typeRepr)) + typeRepr = specifier->getBase(); + + inferenceSources.emplace_back(typeRepr, type); + } + + // Gather requirements from the result type. + auto *resultTypeRepr = [&subscr, &func]() -> TypeRepr * { + if (subscr) { + return subscr->getElementTypeLoc().getTypeRepr(); + } else if (auto *FD = dyn_cast(func)) { + return FD->getBodyResultTypeLoc().getTypeRepr(); + } else { + return nullptr; + } + }(); + if (resultTypeRepr && !isa(resultTypeRepr)) { + auto resultType = resolution.resolveType( + resultTypeRepr, TypeResolverContext::FunctionResult); + + inferenceSources.emplace_back(resultTypeRepr, resultType); + } + } + } else if (auto *ext = dyn_cast(GC)) { + // Form the interface type of the extension so we can use it as an inference + // source. + // + // FIXME: Push this into the "get interface type" request. + bool mustInferRequirements = false; + Type extInterfaceType = + formExtensionInterfaceType(ext, ext->getExtendedType(), + gp, sameTypeReqs, + mustInferRequirements); + + auto cannotReuseNominalSignature = [&]() -> bool { + const auto finalDepth = gp->getParams().back()->getDepth(); + return mustInferRequirements + || !sameTypeReqs.empty() + || ext->getTrailingWhereClause() + || (getExtendedTypeGenericDepth(ext) != finalDepth); + }; + + // Re-use the signature of the type being extended by default. + if (!cannotReuseNominalSignature()) { + return ext->getSelfNominalTypeDecl()->getGenericSignatureOfContext(); + } - gp->setDepth(typeDecl->getGenericContextDepth()); + // Allow parameters to be equated with concrete types. + allowConcreteGenericParams = true; + inferenceSources.emplace_back(nullptr, extInterfaceType); + } - auto *sig = TypeChecker::checkGenericSignature( - gp, dc, - dc->getGenericSignatureOfContext(), - /*allowConcreteGenericParams=*/false); - typeDecl->setGenericSignature(sig); + // EGREGIOUS HACK: The GSB cannot handle the addition of parent signatures + // from malformed decls in many cases. Check the invalid bit and null out the + // parent signature. + auto *parentSig = GC->getParent()->getGenericSignatureOfContext(); + if (auto *DD = GC->getParent()->getAsDecl()) { + parentSig = DD->isInvalid() ? nullptr : parentSig; + } + + return TypeChecker::checkGenericSignature( + gp, GC, parentSig, + allowConcreteGenericParams, + sameTypeReqs, inferenceSources); } /// diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index d3f160212a0db..7083a84097486 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -864,6 +864,26 @@ class TypeChecker final : public LazyResolver { static Type substMemberTypeWithBase(ModuleDecl *module, TypeDecl *member, Type baseTy, bool useArchetypes = true); + /// Determine whether this is a "pass-through" typealias, which has the + /// same type parameters as the nominal type it references and specializes + /// the underlying nominal type with exactly those type parameters. + /// For example, the following typealias \c GX is a pass-through typealias: + /// + /// \code + /// struct X { } + /// typealias GX = X + /// \endcode + /// + /// whereas \c GX2 and \c GX3 are not pass-through because \c GX2 has + /// different type parameters and \c GX3 doesn't pass its type parameters + /// directly through. + /// + /// \code + /// typealias GX2 = X + /// typealias GX3 = X + /// \endcode + static bool isPassThroughTypealias(TypeAliasDecl *typealias); + /// Determine whether one type is a subtype of another. /// /// \param t1 The potential subtype. @@ -1013,13 +1033,6 @@ class TypeChecker final : public LazyResolver { /// Infer default value witnesses for all requirements in the given protocol. void inferDefaultWitnesses(ProtocolDecl *proto); - /// Compute the generic signature, generic environment and interface type - /// of a generic function or subscript. - void validateGenericFuncOrSubscriptSignature( - PointerUnion - funcOrSubscript, - ValueDecl *decl, GenericContext *genCtx); - /// For a generic requirement in a protocol, make sure that the requirement /// set didn't add any requirements to Self or its associated types. void checkProtocolSelfRequirements(ValueDecl *decl); @@ -1055,11 +1068,6 @@ class TypeChecker final : public LazyResolver { SmallVector additionalRequirements = {}, SmallVector inferenceSources = {}); - /// Validate the signature of a generic type. - /// - /// \param nominal The generic type. - void validateGenericTypeSignature(GenericTypeDecl *nominal); - /// Create a text string that describes the bindings of generic parameters /// that are relevant to the given set of types, e.g., /// "[with T = Bar, U = Wibble]". From d68f1259d7200b7ef9193724ee383d51cf0aaf98 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 11 Sep 2019 12:54:54 -0700 Subject: [PATCH 024/199] Teach the ASTVerifier not to force generic signatures The ASTVerifier is called by parsing tests and IDE tests that may not necessarily set up a typechecker. Remove the verifier's ability to force computing generic signatures so we don't accidentally wander into the typechecker and crash. --- lib/AST/ASTVerifier.cpp | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp index 54d0d957fa50a..96f3a1a106463 100644 --- a/lib/AST/ASTVerifier.cpp +++ b/lib/AST/ASTVerifier.cpp @@ -167,15 +167,32 @@ std::pair dispatchVisitPreExprHelper( } namespace { - /// Retrieve the "overridden" declaration of this declaration, but only if - // it's already been computed. - template - T *getOverriddenDeclIfAvailable(T *decl) { - if (!decl->overriddenDeclsComputed()) return nullptr; +// Retrieve the "overridden" declaration of this declaration, but only if +// it's already been computed. +template T *getOverriddenDeclIfAvailable(T *decl) { + if (!decl->overriddenDeclsComputed()) + return nullptr; - return cast_or_null(decl->getOverriddenDecl()); - } + return cast_or_null(decl->getOverriddenDecl()); } + +// Retrieve the generic signature of the innermost context that has been forced +// so far. +// +// This avoids kicking off the request for a generic signature in the verifier. +static GenericSignature * +getNearestForcedGenericSignatureOfContext(DeclContext *dc) { + do { + if (auto decl = dc->getAsDecl()) + if (auto GC = decl->getAsGenericContext()) + if (GC->hasComputedGenericSignature()) + return GC->getGenericSignature(); + } while ((dc = dc->getParent())); + + return nullptr; +} +} // namespace + class Verifier : public ASTWalker { PointerUnion M; ASTContext &Ctx; @@ -686,14 +703,14 @@ class Verifier : public ASTWalker { void pushScope(DeclContext *scope) { Scopes.push_back(scope); - GenericSig.push_back(scope->getGenericSignatureOfContext()); + GenericSig.push_back(::getNearestForcedGenericSignatureOfContext(scope)); } void pushScope(BraceStmt *scope) { Scopes.push_back(scope); } void popScope(DeclContext *scope) { assert(Scopes.back().get() == scope); - assert(GenericSig.back() == scope->getGenericSignatureOfContext()); + assert(GenericSig.back() == ::getNearestForcedGenericSignatureOfContext(scope)); Scopes.pop_back(); GenericSig.pop_back(); } From e0a41b19cb5044546fca507fa19a0f2efe49f27e Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 11 Sep 2019 12:56:12 -0700 Subject: [PATCH 025/199] Break some cycles Computing the generic signature changes the way that cycles appear in the compiler. For now, break these cycles. We should investigate each place where hasComputedGenericSignature() is used in service of breaking cycles. See rdar://55263708 --- lib/AST/GenericSignatureBuilder.cpp | 6 ++++++ lib/AST/ProtocolConformance.cpp | 19 ++++++++++--------- lib/Sema/ConstraintSystem.cpp | 4 +++- lib/Sema/MiscDiagnostics.cpp | 10 +++++++--- lib/Sema/TypeCheckDecl.cpp | 5 ++--- lib/Sema/TypeCheckProtocolInference.cpp | 9 +++++---- lib/Sema/TypeCheckType.cpp | 2 +- test/decl/nested/protocol.swift | 10 ++++++---- test/decl/overload.swift | 12 +++++++----- 9 files changed, 47 insertions(+), 30 deletions(-) diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp index 5d6a614bd6ca6..ea2536b296ea8 100644 --- a/lib/AST/GenericSignatureBuilder.cpp +++ b/lib/AST/GenericSignatureBuilder.cpp @@ -5296,6 +5296,12 @@ class GenericSignatureBuilder::InferRequirementsWalker : public TypeWalker { auto decl = ty->getAnyNominal(); if (!decl) return Action::Continue; + // FIXME: The GSB and the request evaluator both detect a cycle here if we + // force a recursive generic signature. We should look into moving cycle + // detection into the generic signature request(s) - see rdar://55263708 + if (!decl->hasComputedGenericSignature()) + return Action::Continue; + auto genericSig = decl->getGenericSignature(); if (!genericSig) return Action::Continue; diff --git a/lib/AST/ProtocolConformance.cpp b/lib/AST/ProtocolConformance.cpp index 3a210c62a4d15..82a6ea1396799 100644 --- a/lib/AST/ProtocolConformance.cpp +++ b/lib/AST/ProtocolConformance.cpp @@ -547,17 +547,9 @@ void NormalProtocolConformance::differenceAndStoreConditionalRequirements() return; } - auto extensionSig = ext->getGenericSignature(); - if (!extensionSig) { - if (auto lazyResolver = ctxt.getLazyResolver()) { - lazyResolver->resolveExtension(ext); - extensionSig = ext->getGenericSignature(); - } - } - // The type is generic, but the extension doesn't have a signature yet, so // we might be in a recursive validation situation. - if (!extensionSig) { + if (!ext->hasComputedGenericSignature()) { // If the extension is invalid, it won't ever get a signature, so we // "succeed" with an empty result instead. if (ext->isInvalid()) { @@ -569,6 +561,15 @@ void NormalProtocolConformance::differenceAndStoreConditionalRequirements() failure(); return; } + + // FIXME: All of this will be removed when validateExtension goes away. + auto extensionSig = ext->getGenericSignature(); + if (!extensionSig) { + if (auto lazyResolver = ctxt.getLazyResolver()) { + lazyResolver->resolveExtension(ext); + extensionSig = ext->getGenericSignature(); + } + } auto canExtensionSig = extensionSig->getCanonicalSignature(); auto canTypeSig = typeSig->getCanonicalSignature(); diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 44ec7fa4f1973..0cc784254e508 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -501,7 +501,9 @@ Type ConstraintSystem::openUnboundGenericType(UnboundGenericType *unbound, // If the unbound decl hasn't been validated yet, we have a circular // dependency that isn't being diagnosed properly. - if (!unboundDecl->getGenericSignature()) { + // + // FIXME: Delete this condition. He's dead Jim. + if (!unboundDecl->hasComputedGenericSignature()) { TC.diagnose(unboundDecl, diag::circular_reference); return Type(); } diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index e79c864e408d0..c4cf00b7fb28d 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -1478,9 +1478,13 @@ bool TypeChecker::getDefaultGenericArgumentsString( genericParamText << contextTy; }; - interleave(typeDecl->getInnermostGenericParamTypes(), - printGenericParamSummary, [&]{ genericParamText << ", "; }); - + // FIXME: We can potentially be in the middle of creating a generic signature + // if we get here. Break this cycle. + if (typeDecl->hasComputedGenericSignature()) { + interleave(typeDecl->getInnermostGenericParamTypes(), + printGenericParamSummary, [&]{ genericParamText << ", "; }); + } + genericParamText << ">"; return true; } diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 125bf63f41aa4..ad318c6051f46 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -3720,8 +3720,8 @@ static void validateResultType(TypeChecker &TC, resultTyLoc.setType( TC.getOrCreateOpaqueResultType(resolution, decl, opaqueTy)); } else { - TC.validateType(resultTyLoc, resolution, - TypeResolverContext::FunctionResult); + TypeChecker::validateType(TC.Context, resultTyLoc, resolution, + TypeResolverContext::FunctionResult); } } @@ -3862,7 +3862,6 @@ void TypeChecker::validateDecl(ValueDecl *D) { for (auto member : proto->getMembers()) { if (auto *aliasDecl = dyn_cast(member)) { if (!aliasDecl->isGeneric()) { - assert(aliasDecl->getGenericSignature() == proto->getGenericSignature()); // FIXME: Force creation of the protocol's generic environment now. (void) proto->getGenericEnvironment(); diff --git a/lib/Sema/TypeCheckProtocolInference.cpp b/lib/Sema/TypeCheckProtocolInference.cpp index de33075c90ccf..ead35bb9bac96 100644 --- a/lib/Sema/TypeCheckProtocolInference.cpp +++ b/lib/Sema/TypeCheckProtocolInference.cpp @@ -197,10 +197,11 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses( // Build a generic signature. tc.validateExtension(extension); - // The extension may not have a generic signature set up yet, as a - // recursion breaker, in which case we can't yet confidently reject its - // witnesses. - if (!extension->getGenericSignature()) + // FIXME: The extension may not have a generic signature set up yet as + // resolving signatures may trigger associated type inference. This cycle + // is now detectable and we should look into untangling it + // - see rdar://55263708 + if (!extension->hasComputedGenericSignature()) return true; // The condition here is a bit more fickle than diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index e46ba1bcba7d2..abe05c5118fd8 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -977,7 +977,7 @@ static Type resolveTypeDecl(TypeDecl *typeDecl, SourceLoc loc, if (!options.is(TypeResolverContext::ExtensionBinding) || !isa(typeDecl)) { // Validate the declaration. - if (lazyResolver) + if (lazyResolver && !typeDecl->hasInterfaceType()) lazyResolver->resolveDeclSignature(typeDecl); // If we were not able to validate recursively, bail out. diff --git a/test/decl/nested/protocol.swift b/test/decl/nested/protocol.swift index 7db8326c98b92..2d49b831ad82a 100644 --- a/test/decl/nested/protocol.swift +++ b/test/decl/nested/protocol.swift @@ -57,10 +57,10 @@ protocol SillyProtocol { class InnerClass {} // expected-error {{type 'InnerClass' cannot be nested in protocol 'SillyProtocol'}} } +// N.B. Redeclaration checks don't see this case because `protocol A` is invalid. enum OuterEnum { protocol C {} // expected-error{{protocol 'C' cannot be nested inside another declaration}} - // expected-note@-1{{'C' previously declared here}} - case C(C) // expected-error{{invalid redeclaration of 'C'}} + case C(C) } class OuterClass { @@ -105,7 +105,9 @@ func testLookup(_ x: OuterForUFI.Inner) { x.req() x.extMethod() } + +// N.B. Lookup fails here because OuterForUFI.Inner is marked invalid. func testLookup(_ x: T) { - x.req() - x.extMethod() + x.req() // expected-error {{value of type 'T' has no member 'req'}} + x.extMethod() // expected-error {{value of type 'T' has no member 'extMethod'}} } diff --git a/test/decl/overload.swift b/test/decl/overload.swift index 68d3d8dec68f0..9a74468dc430b 100644 --- a/test/decl/overload.swift +++ b/test/decl/overload.swift @@ -536,9 +536,10 @@ enum SR_10084_E_2 { } } +// N.B. Redeclaration checks don't see this case because `protocol A` is invalid. enum SR_10084_E_3 { - protocol A {} //expected-error {{protocol 'A' cannot be nested inside another declaration}} // expected-note {{'A' previously declared here}} - case A // expected-error {{invalid redeclaration of 'A'}} + protocol A {} //expected-error {{protocol 'A' cannot be nested inside another declaration}} + case A } enum SR_10084_E_4 { @@ -551,9 +552,10 @@ enum SR_10084_E_5 { case C // expected-error {{invalid redeclaration of 'C'}} } +// N.B. Redeclaration checks don't see this case because `protocol D` is invalid. enum SR_10084_E_6 { - case D // expected-note {{'D' previously declared here}} - protocol D {} //expected-error {{protocol 'D' cannot be nested inside another declaration}} // expected-error {{invalid redeclaration of 'D'}} + case D + protocol D {} //expected-error {{protocol 'D' cannot be nested inside another declaration}} } enum SR_10084_E_7 { @@ -604,4 +606,4 @@ enum SR_10084_E_15 { enum SR_10084_E_16 { typealias Z = Int // expected-note {{'Z' previously declared here}} case Z // expected-error {{invalid redeclaration of 'Z'}} -} \ No newline at end of file +} From 173e4526ee733d7fe6d2f4b0c8ab9d92d9b2015b Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Mon, 16 Sep 2019 14:26:44 -0700 Subject: [PATCH 026/199] [Diagnostics] Adjust wording of type_cannot_conform error message. --- include/swift/AST/DiagnosticsSema.def | 5 +-- lib/Sema/CSDiagnostics.cpp | 32 ++++++++++--------- lib/Sema/CSDiagnostics.h | 4 +++ lib/Sema/TypeCheckProtocol.cpp | 2 +- test/Constraints/diagnostics.swift | 8 ++--- test/Constraints/function_builder_diags.swift | 2 +- test/type/opaque.swift | 2 +- .../rdar27830834.swift | 2 +- .../0196-rdar48937223.swift | 2 +- 9 files changed, 33 insertions(+), 26 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index cb72735308779..7f37e16bb2efc 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1661,8 +1661,9 @@ ERROR(use_of_equal_instead_of_equality,none, "use of '=' in a boolean context, did you mean '=='?", ()) ERROR(type_cannot_conform, none, - "%0 type %1 cannot conform to %2; only struct/enum/class " - "types can conform to protocols", (StringRef, Type, Type)) + "%select{|protocol }0type %1 cannot conform to %2; " + "only struct/enum/class types can conform to protocols", + (bool, Type, Type)) ERROR(protocol_does_not_conform_static,none, "%0 cannot be used as a type conforming to protocol %1 because %1 " "has static requirements", diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index ce38aac992347..8582a5a21620b 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -576,21 +576,8 @@ bool MissingConformanceFailure::diagnoseAsError() { return true; } - // Diagnose types that cannot conform to protocols. - Optional prohibitedTypeKind = None; - if (nonConformingType->is()) - prohibitedTypeKind = "function"; - else if (nonConformingType->is()) - prohibitedTypeKind = "tuple"; - else if (nonConformingType->isExistentialType()) - prohibitedTypeKind = "protocol"; - else if (nonConformingType->is()) - prohibitedTypeKind = "metatype"; - - if (prohibitedTypeKind.hasValue()) { - emitDiagnostic(anchor->getLoc(), diag::type_cannot_conform, - *prohibitedTypeKind, nonConformingType, protocolType); - return true; + if (diagnoseTypeCannotConform(anchor, nonConformingType, protocolType)) { + return true; } if (atParameterPos) { @@ -608,6 +595,21 @@ bool MissingConformanceFailure::diagnoseAsError() { return RequirementFailure::diagnoseAsError(); } +bool MissingConformanceFailure::diagnoseTypeCannotConform(Expr *anchor, + Type nonConformingType, Type protocolType) const { + if (nonConformingType->is() || + nonConformingType->is() || + nonConformingType->isExistentialType() || + nonConformingType->is()) { + emitDiagnostic(anchor->getLoc(), diag::type_cannot_conform, + nonConformingType->isExistentialType(), nonConformingType, + protocolType); + return true; + } + + return false; +} + Optional> GenericArgumentsMismatchFailure::getDiagnosticFor( ContextualTypePurpose context) { switch (context) { diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index e13b224ec92e3..db294900e72ab 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -356,6 +356,10 @@ class MissingConformanceFailure final : public RequirementFailure { DiagAsNote getDiagnosticAsNote() const override { return diag::candidate_types_conformance_requirement; } + +private: + bool diagnoseTypeCannotConform(Expr *anchor, Type nonConformingType, + Type protocolType) const; }; /// Diagnose failures related to same-type generic requirements, e.g. diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index e5010c2002df6..cd4f9cbde668d 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -3970,7 +3970,7 @@ static void diagnoseConformanceFailure(Type T, TypeChecker::containsProtocol(T, Proto, DC, None)) { if (!T->isObjCExistentialType()) { - diags.diagnose(ComplainLoc, diag::type_cannot_conform, "protocol", + diags.diagnose(ComplainLoc, diag::type_cannot_conform, true, T, Proto->getDeclaredType()); return; } diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index 166b5bd73e503..8f6fce9033deb 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -47,9 +47,9 @@ f0(i, i, // Cannot conform to protocols. -f5(f4) // expected-error {{function type '(Int) -> Int' cannot conform to 'P2'; only struct/enum/class types can conform to protocols}} -f5((1, "hello")) // expected-error {{tuple type '(Int, String)' cannot conform to 'P2'; only struct/enum/class types can conform to protocols}} -f5(Int.self) // expected-error {{metatype type 'Int.Type' cannot conform to 'P2'; only struct/enum/class types can conform to protocols}} +f5(f4) // expected-error {{type '(Int) -> Int' cannot conform to 'P2'; only struct/enum/class types can conform to protocols}} +f5((1, "hello")) // expected-error {{type '(Int, String)' cannot conform to 'P2'; only struct/enum/class types can conform to protocols}} +f5(Int.self) // expected-error {{type 'Int.Type' cannot conform to 'P2'; only struct/enum/class types can conform to protocols}} // Tuple element not convertible. f0(i, @@ -99,7 +99,7 @@ func f8(_ n: T, _ f: @escaping (T) -> T) {} f8(3, f4) // expected-error {{argument type 'Int' does not conform to expected type 'P2'}} typealias Tup = (Int, Double) func f9(_ x: Tup) -> Tup { return x } -f8((1,2.0), f9) // expected-error {{tuple type 'Tup' (aka '(Int, Double)') cannot conform to 'P2'; only struct/enum/class types can conform to protocols}} +f8((1,2.0), f9) // expected-error {{type 'Tup' (aka '(Int, Double)') cannot conform to 'P2'; only struct/enum/class types can conform to protocols}} // QoI: Incorrect diagnostic for calling nonexistent members on literals 1.doesntExist(0) // expected-error {{value of type 'Int' has no member 'doesntExist'}} diff --git a/test/Constraints/function_builder_diags.swift b/test/Constraints/function_builder_diags.swift index 47800391e4303..95c96d566c636 100644 --- a/test/Constraints/function_builder_diags.swift +++ b/test/Constraints/function_builder_diags.swift @@ -166,7 +166,7 @@ struct Label : P where L : P { // expected-note {{'L' declared as parameter t } func test_51167632() -> some P { - AnyP(G { // expected-error {{metatype type 'Label.Type' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} + AnyP(G { // expected-error {{type 'Label.Type' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} Text("hello") Label // expected-error {{generic parameter 'L' could not be inferred}} // expected-note@-1 {{explicitly specify the generic arguments to fix this issue}} {{10-10=<<#L: P#>>}} diff --git a/test/type/opaque.swift b/test/type/opaque.swift index 79101dd4b29f6..15d69f70225e1 100644 --- a/test/type/opaque.swift +++ b/test/type/opaque.swift @@ -377,7 +377,7 @@ protocol P_51641323 { func rdar_51641323() { struct Foo: P_51641323 { var foo: some P_51641323 { {} } - // expected-error@-1 {{function type '() -> ()' cannot conform to 'P_51641323'; only struct/enum/class types can conform to protocols}} + // expected-error@-1 {{type '() -> ()' cannot conform to 'P_51641323'; only struct/enum/class types can conform to protocols}} } } diff --git a/validation-test/Sema/type_checker_crashers_fixed/rdar27830834.swift b/validation-test/Sema/type_checker_crashers_fixed/rdar27830834.swift index 76a2d225baca6..9776ec796afe3 100644 --- a/validation-test/Sema/type_checker_crashers_fixed/rdar27830834.swift +++ b/validation-test/Sema/type_checker_crashers_fixed/rdar27830834.swift @@ -1,4 +1,4 @@ // RUN: %target-swift-frontend %s -typecheck -verify var d = [String:String]() -_ = "\(d.map{ [$0 : $0] })" // expected-error {{tuple type '(key: String, value: String)' cannot conform to 'Hashable'; only struct/enum/class types can conform to protocols}} +_ = "\(d.map{ [$0 : $0] })" // expected-error {{type '(key: String, value: String)' cannot conform to 'Hashable'; only struct/enum/class types can conform to protocols}} diff --git a/validation-test/compiler_crashers_2_fixed/0196-rdar48937223.swift b/validation-test/compiler_crashers_2_fixed/0196-rdar48937223.swift index b0d2b824d2659..2abfc949c9d98 100644 --- a/validation-test/compiler_crashers_2_fixed/0196-rdar48937223.swift +++ b/validation-test/compiler_crashers_2_fixed/0196-rdar48937223.swift @@ -5,7 +5,7 @@ protocol P {} func fn(_ arg1: T, arg2: (T) -> U) {} func test(str: String) { - fn(str) { arg in // expected-error {{tuple type '()' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} + fn(str) { arg in // expected-error {{type '()' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} <#FOO#> // expected-error {{editor placeholder in source file}} } } From 362b21926cd31d4da75e98d384cd7cfdea78564e Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 16 Sep 2019 15:07:19 -0700 Subject: [PATCH 027/199] Revert "Merge pull request #26937 from rintaro/syntaxparse-leakfix" This reverts commit e49401bbca52dad71d6d6390aed8845fa0bed9bf, reversing changes made to bd222ad71cf086eb298a50d9cff61f83ba4a8174. --- lib/Parse/ParseDecl.cpp | 4 +-- lib/Parse/ParseStmt.cpp | 1 - lib/Parse/SyntaxParsingContext.cpp | 14 ++++++-- test/Syntax/serialize_tupletype.swift.result | 38 ++++++++++---------- 4 files changed, 32 insertions(+), 25 deletions(-) diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index a4d2514c0b2ab..599d3ee5b6c6f 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -4125,7 +4125,7 @@ parseDeclTypeAlias(Parser::ParseDeclOptions Flags, DeclAttributes &Attributes) { ParserPosition startPosition = getParserPosition(); llvm::Optional TmpCtxt; TmpCtxt.emplace(SyntaxContext); - TmpCtxt->setBackTracking(); + TmpCtxt->setTransparent(); SourceLoc TypeAliasLoc = consumeToken(tok::kw_typealias); SourceLoc EqualLoc; @@ -4164,13 +4164,13 @@ parseDeclTypeAlias(Parser::ParseDeclOptions Flags, DeclAttributes &Attributes) { } if (Flags.contains(PD_InProtocol) && !genericParams && !Tok.is(tok::equal)) { + TmpCtxt->setBackTracking(); TmpCtxt.reset(); // If we're in a protocol and don't see an '=' this looks like leftover Swift 2 // code intending to be an associatedtype. backtrackToPosition(startPosition); return parseDeclAssociatedType(Flags, Attributes); } - TmpCtxt->setTransparent(); TmpCtxt.reset(); auto *TAD = new (Context) TypeAliasDecl(TypeAliasLoc, EqualLoc, Id, IdLoc, diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index ad4811cc96336..61241c4ff742f 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -123,7 +123,6 @@ ParserStatus Parser::parseExprOrStmt(ASTNode &Result) { if (Tok.is(tok::pound) && Tok.isAtStartOfLine() && peekToken().is(tok::code_complete)) { - SyntaxParsingContext CCCtxt(SyntaxContext, SyntaxContextKind::Decl); consumeToken(); if (CodeCompletion) CodeCompletion->completeAfterPoundDirective(); diff --git a/lib/Parse/SyntaxParsingContext.cpp b/lib/Parse/SyntaxParsingContext.cpp index 65cf131b10373..49680cbf32e29 100644 --- a/lib/Parse/SyntaxParsingContext.cpp +++ b/lib/Parse/SyntaxParsingContext.cpp @@ -256,9 +256,17 @@ ParsedRawSyntaxNode SyntaxParsingContext::finalizeSourceFile() { Layout[1] = std::move(Parts.back()); Parts = Parts.drop_back(); - assert(llvm::all_of(Parts, [](const ParsedRawSyntaxNode& node) { - return node.getKind() == SyntaxKind::CodeBlockItem; - }) && "all top level element must be 'CodeBlockItem'"); + for (auto RawNode : Parts) { + if (RawNode.getKind() != SyntaxKind::CodeBlockItem) { + // FIXME: Skip toplevel garbage nodes for now. we shouldn't emit them in + // the first place. + if (RawNode.isRecorded()) + getSyntaxCreator().finalizeNode(RawNode.getOpaqueNode()); + continue; + } + + AllTopLevel.push_back(RawNode); + } Layout[0] = Recorder.recordRawSyntax(SyntaxKind::CodeBlockItemList, Parts); diff --git a/test/Syntax/serialize_tupletype.swift.result b/test/Syntax/serialize_tupletype.swift.result index c186b51c93d6b..d79659405b3d7 100644 --- a/test/Syntax/serialize_tupletype.swift.result +++ b/test/Syntax/serialize_tupletype.swift.result @@ -17,7 +17,7 @@ null, null, { - "id": 33, + "id": 1, "tokenKind": { "kind": "kw_typealias" }, @@ -48,7 +48,7 @@ "presence": "Present" }, { - "id": 34, + "id": 2, "tokenKind": { "kind": "identifier", "text": "x" @@ -64,11 +64,11 @@ }, null, { - "id": 32, + "id": 34, "kind": "TypeInitializerClause", "layout": [ { - "id": 1, + "id": 3, "tokenKind": { "kind": "equal" }, @@ -82,11 +82,11 @@ "presence": "Present" }, { - "id": 31, + "id": 33, "kind": "TupleType", "layout": [ { - "id": 18, + "id": 20, "tokenKind": { "kind": "l_paren" }, @@ -95,16 +95,16 @@ "presence": "Present" }, { - "id": 29, + "id": 31, "kind": "TupleTypeElementList", "layout": [ { - "id": 24, + "id": 26, "kind": "TupleTypeElement", "layout": [ null, { - "id": 19, + "id": 21, "tokenKind": { "kind": "identifier", "text": "b" @@ -115,7 +115,7 @@ }, null, { - "id": 20, + "id": 22, "tokenKind": { "kind": "colon" }, @@ -129,11 +129,11 @@ "presence": "Present" }, { - "id": 22, + "id": 24, "kind": "SimpleTypeIdentifier", "layout": [ { - "id": 21, + "id": 23, "tokenKind": { "kind": "identifier", "text": "Int" @@ -149,7 +149,7 @@ null, null, { - "id": 23, + "id": 25, "tokenKind": { "kind": "comma" }, @@ -166,12 +166,12 @@ "presence": "Present" }, { - "id": 28, + "id": 30, "kind": "TupleTypeElement", "layout": [ null, { - "id": 25, + "id": 27, "tokenKind": { "kind": "kw__" }, @@ -181,7 +181,7 @@ }, null, { - "id": 20, + "id": 22, "tokenKind": { "kind": "colon" }, @@ -195,11 +195,11 @@ "presence": "Present" }, { - "id": 27, + "id": 29, "kind": "SimpleTypeIdentifier", "layout": [ { - "id": 26, + "id": 28, "tokenKind": { "kind": "identifier", "text": "String" @@ -222,7 +222,7 @@ "presence": "Present" }, { - "id": 30, + "id": 32, "tokenKind": { "kind": "r_paren" }, From 6dc63e21e954536fc7755df62c80cfa0715d2c26 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 16 Sep 2019 15:08:46 -0700 Subject: [PATCH 028/199] Revert "Merge pull request #27190 from compnerd/27132" This reverts commit 48387919376ecbfaae43fa65504cc9553d2b7e25, reversing changes made to 4c3f044a46d4a8f48b349821072a09e544142af1. --- include/swift/Parse/SyntaxParsingContext.h | 2 +- lib/Parse/ParseType.cpp | 9 ++++----- lib/Parse/SyntaxParsingContext.cpp | 6 +++--- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/include/swift/Parse/SyntaxParsingContext.h b/include/swift/Parse/SyntaxParsingContext.h index 2db8e6e9058c1..6df76bebca037 100644 --- a/include/swift/Parse/SyntaxParsingContext.h +++ b/include/swift/Parse/SyntaxParsingContext.h @@ -300,7 +300,7 @@ class alignas(1 << SyntaxAlignInBits) SyntaxParsingContext { return SyntaxNode(std::move(rawNode)); } - ParsedTokenSyntax &&popToken(); + ParsedTokenSyntax popToken(); /// Create a node using the tail of the collected parts. The number of parts /// is automatically determined from \c Kind. Node: limited number of \c Kind diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 7b4eaf46862a9..69f9c38c66134 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -408,7 +408,7 @@ Parser::TypeASTResult Parser::parseType(Diag<> MessageID, } if (Tok.is(tok::arrow)) { - auto InputNode(std::move(SyntaxContext->popIf().getValue())); + auto InputNode = SyntaxContext->popIf().getValue(); // Handle type-function if we have an arrow. auto ArrowLoc = Tok.getLoc(); auto Arrow = consumeTokenSyntax(); @@ -741,7 +741,7 @@ Parser::TypeResult Parser::parseTypeIdentifier() { if (Base) { SyntaxContext->addSyntax(std::move(*Base)); auto T = SyntaxContext->topNode(); - Junk.push_back(std::move(*SyntaxContext->popIf())); + Junk.push_back(*SyntaxContext->popIf()); ITR = dyn_cast(Generator.generate(T, BaseLoc)); } @@ -1164,10 +1164,9 @@ Parser::TypeResult Parser::parseTypeTupleBody() { auto InFlight = diagnose(EqualLoc, diag::tuple_type_init); if (Init.isNonNull()) InFlight.fixItRemove(SourceRange(EqualLoc, Init.get()->getEndLoc())); + auto Expr = *SyntaxContext->popIf(); Initializer = ParsedSyntaxRecorder::makeInitializerClause( - std::move(*Equal), - std::move(*SyntaxContext->popIf()), - *SyntaxContext); + std::move(*Equal), std::move(Expr), *SyntaxContext); } Comma = consumeTokenSyntaxIf(tok::comma); diff --git a/lib/Parse/SyntaxParsingContext.cpp b/lib/Parse/SyntaxParsingContext.cpp index 49680cbf32e29..e365a87837c51 100644 --- a/lib/Parse/SyntaxParsingContext.cpp +++ b/lib/Parse/SyntaxParsingContext.cpp @@ -163,8 +163,8 @@ const SyntaxParsingContext *SyntaxParsingContext::getRoot() const { return Curr; } -ParsedTokenSyntax &&SyntaxParsingContext::popToken() { - return std::move(popIf().getValue()); +ParsedTokenSyntax SyntaxParsingContext::popToken() { + return popIf().getValue(); } /// Add Token with Trivia to the parts. @@ -342,7 +342,7 @@ SyntaxParsingContext::~SyntaxParsingContext() { Storage.push_back(std::move(BridgedNode.getValue())); } } else { - auto node(std::move(bridgeAs(CtxtKind, getParts()).getValue())); + auto node = bridgeAs(CtxtKind, getParts()).getValue(); Storage.erase(Storage.begin() + Offset, Storage.end()); Storage.emplace_back(std::move(node)); } From d8aaf29617b474fe47bd55a3c3145af2566c044f Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 16 Sep 2019 15:10:33 -0700 Subject: [PATCH 029/199] Revert "Merge pull request #27132 from rintaro/syntaxparse-parsedrawsyntax-moveonly" This reverts commit e675c4947d155c548b61b2ef27a255a4d436e37c, reversing changes made to 73315ba01ea98b078b84179eb435e89db956bdc7. --- include/swift/Parse/HiddenLibSyntaxAction.h | 2 - include/swift/Parse/LibSyntaxGenerator.h | 4 +- include/swift/Parse/ParsedRawSyntaxNode.h | 103 +------ include/swift/Parse/ParsedRawSyntaxRecorder.h | 4 +- include/swift/Parse/ParsedSyntax.h | 9 +- .../swift/Parse/ParsedSyntaxRecorder.h.gyb | 25 +- include/swift/Parse/SyntaxParseActions.h | 7 - include/swift/Parse/SyntaxParserResult.h | 37 +-- include/swift/Parse/SyntaxParsingContext.h | 21 +- include/swift/SyntaxParse/SyntaxTreeCreator.h | 2 - lib/Parse/HiddenLibSyntaxAction.cpp | 9 - lib/Parse/ParseExpr.cpp | 34 +-- lib/Parse/ParsePattern.cpp | 1 - lib/Parse/ParseType.cpp | 287 +++++++++--------- lib/Parse/ParsedRawSyntaxNode.cpp | 15 +- lib/Parse/ParsedRawSyntaxRecorder.cpp | 34 +-- lib/Parse/ParsedSyntaxBuilders.cpp.gyb | 4 +- lib/Parse/ParsedSyntaxNodes.cpp.gyb | 6 +- lib/Parse/ParsedSyntaxRecorder.cpp.gyb | 57 ++-- lib/Parse/Parser.cpp | 19 +- lib/Parse/SyntaxParsingContext.cpp | 72 +++-- lib/SyntaxParse/RawSyntaxTokenCache.h | 3 +- lib/SyntaxParse/SyntaxTreeCreator.cpp | 6 - .../libSwiftSyntaxParser.cpp | 4 - 24 files changed, 294 insertions(+), 471 deletions(-) diff --git a/include/swift/Parse/HiddenLibSyntaxAction.h b/include/swift/Parse/HiddenLibSyntaxAction.h index 7f26db622a1f2..0b42bcc0c706a 100644 --- a/include/swift/Parse/HiddenLibSyntaxAction.h +++ b/include/swift/Parse/HiddenLibSyntaxAction.h @@ -70,8 +70,6 @@ class HiddenLibSyntaxAction : public SyntaxParseActions { std::pair lookupNode(size_t lexerOffset, syntax::SyntaxKind kind) override; - void discardRecordedNode(OpaqueSyntaxNode node) override; - OpaqueSyntaxNodeKind getOpaqueKind() override { return ExplicitAction->getOpaqueKind(); } diff --git a/include/swift/Parse/LibSyntaxGenerator.h b/include/swift/Parse/LibSyntaxGenerator.h index 1333ed74af219..66698411dcc2c 100644 --- a/include/swift/Parse/LibSyntaxGenerator.h +++ b/include/swift/Parse/LibSyntaxGenerator.h @@ -44,7 +44,7 @@ class LibSyntaxGenerator { auto Recorded = Recorder.recordToken(Kind, Range, LeadingTriviaPieces, TrailingTriviaPieces); - auto Raw = static_cast(Recorded.takeOpaqueNode()); + auto Raw = static_cast(Recorded.getOpaqueNode()); return make(Raw); } @@ -55,7 +55,7 @@ class LibSyntaxGenerator { auto Children = Node.getDeferredChildren(); auto Recorded = Recorder.recordRawSyntax(Kind, Children); - RC Raw {static_cast(Recorded.takeOpaqueNode()) }; + RC Raw {static_cast(Recorded.getOpaqueNode()) }; Raw->Release(); // -1 since it's transfer of ownership. return make(Raw); } diff --git a/include/swift/Parse/ParsedRawSyntaxNode.h b/include/swift/Parse/ParsedRawSyntaxNode.h index 2c80ee7b89de1..5df7656e4c364 100644 --- a/include/swift/Parse/ParsedRawSyntaxNode.h +++ b/include/swift/Parse/ParsedRawSyntaxNode.h @@ -51,7 +51,7 @@ class ParsedRawSyntaxNode { CharSourceRange Range; }; struct DeferredLayoutNode { - MutableArrayRef Children; + ArrayRef Children; }; struct DeferredTokenNode { const ParsedTriviaPiece *TriviaPieces; @@ -73,8 +73,8 @@ class ParsedRawSyntaxNode { bool IsMissing = false; ParsedRawSyntaxNode(syntax::SyntaxKind k, - MutableArrayRef deferredNodes) - : DeferredLayout({deferredNodes}), + ArrayRef deferredNodes) + : DeferredLayout{deferredNodes}, SynKind(uint16_t(k)), TokKind(uint16_t(tok::unknown)), DK(DataKind::DeferredLayout) { assert(getKind() == k && "Syntax kind with too large value!"); @@ -97,8 +97,6 @@ class ParsedRawSyntaxNode { assert(DeferredToken.NumTrailingTrivia == numTrailingTrivia && "numLeadingTrivia is too large value!"); } - ParsedRawSyntaxNode(ParsedRawSyntaxNode &other) = delete; - ParsedRawSyntaxNode &operator=(ParsedRawSyntaxNode &other) = delete; public: ParsedRawSyntaxNode() @@ -117,35 +115,6 @@ class ParsedRawSyntaxNode { assert(getTokenKind() == tokKind && "Token kind with too large value!"); } - ParsedRawSyntaxNode &operator=(ParsedRawSyntaxNode &&other) { - assert(DK != DataKind::Recorded); - switch (other.DK) { - case DataKind::Null: - break; - case DataKind::Recorded: - RecordedData = std::move(other.RecordedData); - break; - case DataKind::DeferredLayout: - DeferredLayout = std::move(other.DeferredLayout); - break; - case DataKind::DeferredToken: - DeferredToken = std::move(other.DeferredToken); - break; - } - SynKind = std::move(other.SynKind); - TokKind = std::move(other.TokKind); - DK = std::move(other.DK); - IsMissing = std::move(other.IsMissing); - other.reset(); - return *this; - } - ParsedRawSyntaxNode(ParsedRawSyntaxNode &&other) : ParsedRawSyntaxNode() { - *this = std::move(other); - } - ~ParsedRawSyntaxNode() { - assert(DK != DataKind::Recorded); - } - syntax::SyntaxKind getKind() const { return syntax::SyntaxKind(SynKind); } tok getTokenKind() const { return tok(TokKind); } @@ -167,36 +136,6 @@ class ParsedRawSyntaxNode { /// Primary used for a deferred missing token. bool isMissing() const { return IsMissing; } - void reset() { - RecordedData = {}; - SynKind = uint16_t(syntax::SyntaxKind::Unknown); - TokKind = uint16_t(tok::unknown); - DK = DataKind::Null; - IsMissing = false; - } - - ParsedRawSyntaxNode unsafeCopy() const { - ParsedRawSyntaxNode copy; - switch (DK) { - case DataKind::DeferredLayout: - copy.DeferredLayout = DeferredLayout; - break; - case DataKind::DeferredToken: - copy.DeferredToken = DeferredToken; - break; - case DataKind::Recorded: - copy.RecordedData = RecordedData; - break; - case DataKind::Null: - break; - } - copy.SynKind = SynKind; - copy.TokKind = TokKind; - copy.DK = DK; - copy.IsMissing = IsMissing; - return copy; - } - CharSourceRange getDeferredRange() const { switch (DK) { case DataKind::DeferredLayout: @@ -214,24 +153,18 @@ class ParsedRawSyntaxNode { assert(isRecorded()); return RecordedData.Range; } - const OpaqueSyntaxNode &getOpaqueNode() const { + OpaqueSyntaxNode getOpaqueNode() const { assert(isRecorded()); return RecordedData.OpaqueNode; } - OpaqueSyntaxNode takeOpaqueNode() { - assert(isRecorded()); - auto opaque = RecordedData.OpaqueNode; - reset(); - return opaque; - } // Deferred Layout Data ====================================================// CharSourceRange getDeferredLayoutRange() const { assert(DK == DataKind::DeferredLayout); assert(!DeferredLayout.Children.empty()); - auto getLastNonNullChild = [this]() -> const ParsedRawSyntaxNode & { - for (auto &Child : llvm::reverse(getDeferredChildren())) + auto getLastNonNullChild = [this]() { + for (auto &&Child : llvm::reverse(getDeferredChildren())) if (!Child.isNull()) return Child; llvm_unreachable("layout node without non-null children"); @@ -245,28 +178,6 @@ class ParsedRawSyntaxNode { assert(DK == DataKind::DeferredLayout); return DeferredLayout.Children; } - MutableArrayRef getDeferredChildren() { - assert(DK == DataKind::DeferredLayout); - return DeferredLayout.Children; - } - ParsedRawSyntaxNode copyDeferred() const { - ParsedRawSyntaxNode copy; - switch (DK) { - case DataKind::DeferredLayout: - copy.DeferredLayout = DeferredLayout; - break; - case DataKind::DeferredToken: - copy.DeferredToken = DeferredToken; - break; - default: - llvm_unreachable("node not deferred"); - } - copy.SynKind = SynKind; - copy.TokKind = TokKind; - copy.DK = DK; - copy.IsMissing = IsMissing; - return copy; - } // Deferred Token Data =====================================================// @@ -303,7 +214,7 @@ class ParsedRawSyntaxNode { /// Form a deferred syntax layout node. static ParsedRawSyntaxNode makeDeferred(syntax::SyntaxKind k, - MutableArrayRef deferredNodes, + ArrayRef deferredNodes, SyntaxParsingContext &ctx); /// Form a deferred token node. diff --git a/include/swift/Parse/ParsedRawSyntaxRecorder.h b/include/swift/Parse/ParsedRawSyntaxRecorder.h index 1afe4837fdc76..9ab897b60d7e9 100644 --- a/include/swift/Parse/ParsedRawSyntaxRecorder.h +++ b/include/swift/Parse/ParsedRawSyntaxRecorder.h @@ -60,7 +60,7 @@ class ParsedRawSyntaxRecorder { /// \p kind. Missing optional elements are represented with a null /// ParsedRawSyntaxNode object. ParsedRawSyntaxNode recordRawSyntax(syntax::SyntaxKind kind, - MutableArrayRef elements); + ArrayRef elements); /// Record a raw syntax collecton without eny elements. \p loc can be invalid /// or an approximate location of where an element of the collection would be @@ -68,8 +68,6 @@ class ParsedRawSyntaxRecorder { ParsedRawSyntaxNode recordEmptyRawSyntaxCollection(syntax::SyntaxKind kind, SourceLoc loc); - void discardRecordedNode(ParsedRawSyntaxNode &node); - /// Used for incremental re-parsing. ParsedRawSyntaxNode lookupNode(size_t lexerOffset, SourceLoc loc, syntax::SyntaxKind kind); diff --git a/include/swift/Parse/ParsedSyntax.h b/include/swift/Parse/ParsedSyntax.h index a3c9fdd52e031..61052aaa98f00 100644 --- a/include/swift/Parse/ParsedSyntax.h +++ b/include/swift/Parse/ParsedSyntax.h @@ -26,7 +26,6 @@ class ParsedSyntax { : RawNode(std::move(rawNode)) {} const ParsedRawSyntaxNode &getRaw() const { return RawNode; } - ParsedRawSyntaxNode takeRaw() { return std::move(RawNode); } syntax::SyntaxKind getKind() const { return RawNode.getKind(); } /// Returns true if the syntax node is of the given type. @@ -40,7 +39,7 @@ class ParsedSyntax { template T castTo() const { assert(is() && "castTo() node of incompatible type!"); - return T { RawNode.copyDeferred() }; + return T { RawNode }; } /// If this Syntax node is of the right kind, cast and return it, @@ -53,10 +52,6 @@ class ParsedSyntax { return llvm::None; } - ParsedSyntax copyDeferred() const { - return ParsedSyntax { RawNode.copyDeferred() }; - } - static bool kindof(syntax::SyntaxKind Kind) { return true; } @@ -70,7 +65,7 @@ class ParsedSyntax { class ParsedTokenSyntax final : public ParsedSyntax { public: explicit ParsedTokenSyntax(ParsedRawSyntaxNode rawNode) - : ParsedSyntax(std::move(rawNode)) {} + : ParsedSyntax(rawNode) {} tok getTokenKind() const { return getRaw().getTokenKind(); diff --git a/include/swift/Parse/ParsedSyntaxRecorder.h.gyb b/include/swift/Parse/ParsedSyntaxRecorder.h.gyb index 51b56c73aea07..c81481f6ca46a 100644 --- a/include/swift/Parse/ParsedSyntaxRecorder.h.gyb +++ b/include/swift/Parse/ParsedSyntaxRecorder.h.gyb @@ -53,15 +53,15 @@ public: % elif node.is_syntax_collection(): private: static Parsed${node.name} record${node.syntax_kind}( - MutableArrayRef elts, + ArrayRef elts, ParsedRawSyntaxRecorder &rec); public: static Parsed${node.name} defer${node.syntax_kind}( - MutableArrayRef elts, + ArrayRef elts, SyntaxParsingContext &SPCtx); static Parsed${node.name} make${node.syntax_kind}( - MutableArrayRef elts, + ArrayRef elts, SyntaxParsingContext &SPCtx); static Parsed${node.name} makeBlank${node.syntax_kind}(SourceLoc loc, @@ -69,16 +69,16 @@ public: % elif node.is_unknown(): private: static Parsed${node.name} record${node.syntax_kind}( - MutableArrayRef elts, + ArrayRef elts, ParsedRawSyntaxRecorder &rec); public: static Parsed${node.name} defer${node.syntax_kind}( - MutableArrayRef elts, + ArrayRef elts, SyntaxParsingContext &SPCtx); static Parsed${node.name} make${node.syntax_kind}( - MutableArrayRef elts, + ArrayRef elts, SyntaxParsingContext &SPCtx); % end % end @@ -95,8 +95,8 @@ public: /// optional trailing comma. static ParsedTupleTypeElementSyntax makeTupleTypeElement(ParsedTypeSyntax Type, - Optional TrailingComma, - SyntaxParsingContext &SPCtx); + Optional TrailingComma, + SyntaxParsingContext &SPCtx); /// The provided \c elements are in the appropriate order for the syntax /// \c kind's layout but optional elements are not be included. @@ -104,12 +104,9 @@ public: /// substituting missing parts with a null ParsedRawSyntaxNode object. /// /// \returns true if the layout could be formed, false otherwise. - static bool - formExactLayoutFor(syntax::SyntaxKind kind, - MutableArrayRef elements, - function_ref)> - receiver); + static bool formExactLayoutFor(syntax::SyntaxKind kind, + ArrayRef elements, + function_ref)> receiver); }; } diff --git a/include/swift/Parse/SyntaxParseActions.h b/include/swift/Parse/SyntaxParseActions.h index 33a788ba8e1fa..2a68e132f472b 100644 --- a/include/swift/Parse/SyntaxParseActions.h +++ b/include/swift/Parse/SyntaxParseActions.h @@ -61,13 +61,6 @@ class SyntaxParseActions { ArrayRef elements, CharSourceRange range) = 0; - /// Discard raw syntax node. - /// - /// FIXME: This breaks invariant that any recorded node will be a part of the - /// result SourceFile syntax. This method is a temporary workaround, and - /// should be removed when we fully migrate to libSyntax parsing. - virtual void discardRecordedNode(OpaqueSyntaxNode node) = 0; - /// Used for incremental re-parsing. virtual std::pair lookupNode(size_t lexerOffset, syntax::SyntaxKind kind) { diff --git a/include/swift/Parse/SyntaxParserResult.h b/include/swift/Parse/SyntaxParserResult.h index 6ee74fe398178..28b12ee2390d1 100644 --- a/include/swift/Parse/SyntaxParserResult.h +++ b/include/swift/Parse/SyntaxParserResult.h @@ -40,18 +40,18 @@ template class ParsedSyntaxResult { assert(Status.isError()); } - explicit ParsedSyntaxResult(ParsedRawSyntaxNode &&Raw) - : Raw(std::move(Raw)), Status() {} + explicit ParsedSyntaxResult(ParsedRawSyntaxNode Raw) + : Raw(Raw), Status() {} - explicit ParsedSyntaxResult(ParsedSyntaxNode &&Node) - : ParsedSyntaxResult(Node.takeRaw()) {} + explicit ParsedSyntaxResult(ParsedSyntaxNode Node) + : ParsedSyntaxResult(Node.getRaw()) {} template ::value>::type> - ParsedSyntaxResult(ParsedSyntaxResult &&other) { - Raw = std::move(other.Raw); - Status = std::move(other.Status); + ParsedSyntaxResult(ParsedSyntaxResult other) { + Raw = other.Raw; + Status = other.Status; } bool isSuccess() const { @@ -72,20 +72,11 @@ template class ParsedSyntaxResult { Status.setHasCodeCompletion(); } - ParsedSyntaxNode get() { + ParsedSyntaxNode get() const { assert(!isNull()); - return ParsedSyntaxNode(std::move(Raw)); + return ParsedSyntaxNode(Raw); } - - template - Optional getAs() { - assert(!isNull()); - if (NewSyntaxNode::kindof(Raw.getKind())) - return NewSyntaxNode(std::move(Raw)); - return None; - } - - Optional getOrNull() { + Optional getOrNull() const { if (isNull()) return None; return get(); @@ -103,13 +94,13 @@ template class ParsedSyntaxResult { template static ParsedSyntaxResult makeParsedResult(ParsedSyntaxNode node) { - return ParsedSyntaxResult(std::move(node)); + return ParsedSyntaxResult(node); } template static ParsedSyntaxResult makeParsedError(ParsedSyntaxNode node) { - auto result = ParsedSyntaxResult(std::move(node)); + auto result = ParsedSyntaxResult(node); result.setIsError(); return result; } @@ -122,7 +113,7 @@ static ParsedSyntaxResult makeParsedError() { template static ParsedSyntaxResult makeParsedCodeCompletion(ParsedSyntaxNode node) { - auto result = ParsedSyntaxResult(std::move(node)); + auto result = ParsedSyntaxResult(node); result.setHasCodeCompletion(); return result; } @@ -130,7 +121,7 @@ makeParsedCodeCompletion(ParsedSyntaxNode node) { template static ParsedSyntaxResult makeParsedResult(ParsedSyntaxNode node, ParserStatus Status) { - auto result = ParsedSyntaxResult(std::move(node)); + auto result = ParsedSyntaxResult(node); if (Status.hasCodeCompletion()) result.setHasCodeCompletion(); else if (Status.isError()) diff --git a/include/swift/Parse/SyntaxParsingContext.h b/include/swift/Parse/SyntaxParsingContext.h index 6df76bebca037..383060ddffc10 100644 --- a/include/swift/Parse/SyntaxParsingContext.h +++ b/include/swift/Parse/SyntaxParsingContext.h @@ -180,17 +180,14 @@ class alignas(1 << SyntaxAlignInBits) SyntaxParsingContext { ArrayRef getParts() const { return llvm::makeArrayRef(getStorage()).drop_front(Offset); } - MutableArrayRef getParts() { - return llvm::makeMutableArrayRef(getStorage().data(), getStorage().size()).drop_front(Offset); - } ParsedRawSyntaxNode makeUnknownSyntax(SyntaxKind Kind, - MutableArrayRef Parts); + ArrayRef Parts); ParsedRawSyntaxNode createSyntaxAs(SyntaxKind Kind, - MutableArrayRef Parts, + ArrayRef Parts, SyntaxNodeCreationKind nodeCreateK); Optional bridgeAs(SyntaxContextKind Kind, - MutableArrayRef Parts); + ArrayRef Parts); ParsedRawSyntaxNode finalizeSourceFile(); @@ -280,12 +277,14 @@ class alignas(1 << SyntaxAlignInBits) SyntaxParsingContext { /// Returns the topmost Syntax node. template SyntaxNode topNode() { - ParsedRawSyntaxNode &TopNode = getStorage().back(); + ParsedRawSyntaxNode TopNode = getStorage().back(); + if (TopNode.isRecorded()) { OpaqueSyntaxNode OpaqueNode = TopNode.getOpaqueNode(); return getSyntaxCreator().getLibSyntaxNodeFor(OpaqueNode); } - return getSyntaxCreator().createNode(TopNode.copyDeferred()); + + return getSyntaxCreator().createNode(TopNode); } template @@ -293,11 +292,11 @@ class alignas(1 << SyntaxAlignInBits) SyntaxParsingContext { auto &Storage = getStorage(); if (Storage.size() <= Offset) return llvm::None; - if (!SyntaxNode::kindof(Storage.back().getKind())) + auto rawNode = Storage.back(); + if (!SyntaxNode::kindof(rawNode.getKind())) return llvm::None; - auto rawNode = std::move(Storage.back()); Storage.pop_back(); - return SyntaxNode(std::move(rawNode)); + return SyntaxNode(rawNode); } ParsedTokenSyntax popToken(); diff --git a/include/swift/SyntaxParse/SyntaxTreeCreator.h b/include/swift/SyntaxParse/SyntaxTreeCreator.h index 73af22262299b..26202fa8d7e72 100644 --- a/include/swift/SyntaxParse/SyntaxTreeCreator.h +++ b/include/swift/SyntaxParse/SyntaxTreeCreator.h @@ -64,8 +64,6 @@ class SyntaxTreeCreator: public SyntaxParseActions { ArrayRef elements, CharSourceRange range) override; - void discardRecordedNode(OpaqueSyntaxNode node) override; - std::pair lookupNode(size_t lexerOffset, syntax::SyntaxKind kind) override; diff --git a/lib/Parse/HiddenLibSyntaxAction.cpp b/lib/Parse/HiddenLibSyntaxAction.cpp index 023d01158bae2..9185acf6c7e96 100644 --- a/lib/Parse/HiddenLibSyntaxAction.cpp +++ b/lib/Parse/HiddenLibSyntaxAction.cpp @@ -125,12 +125,3 @@ HiddenLibSyntaxAction::getExplicitNodeFor(OpaqueSyntaxNode node) { auto hiddenNode = (Node *)node; return hiddenNode->ExplicitActionNode; } - -void HiddenLibSyntaxAction::discardRecordedNode(OpaqueSyntaxNode opaqueN) { - if (!opaqueN) - return; - auto node = static_cast(opaqueN); - if (!areBothLibSyntax()) - LibSyntaxAction->discardRecordedNode(node->LibSyntaxNode); - ExplicitAction->discardRecordedNode(node->ExplicitActionNode); -} diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 211cf97860f73..625b10a384705 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -1312,25 +1312,25 @@ ParserResult Parser::parseExprPostfix(Diag<> ID, bool isExprBasic) { template <> ParsedExprSyntax Parser::parseExprSyntax() { auto Token = consumeTokenSyntax(tok::integer_literal); - return ParsedSyntaxRecorder::makeIntegerLiteralExpr(std::move(Token), *SyntaxContext); + return ParsedSyntaxRecorder::makeIntegerLiteralExpr(Token, *SyntaxContext); } template <> ParsedExprSyntax Parser::parseExprSyntax() { auto Token = consumeTokenSyntax(tok::floating_literal); - return ParsedSyntaxRecorder::makeFloatLiteralExpr(std::move(Token), *SyntaxContext); + return ParsedSyntaxRecorder::makeFloatLiteralExpr(Token, *SyntaxContext); } template <> ParsedExprSyntax Parser::parseExprSyntax() { auto Token = consumeTokenSyntax(tok::kw_nil); - return ParsedSyntaxRecorder::makeNilLiteralExpr(std::move(Token), *SyntaxContext); + return ParsedSyntaxRecorder::makeNilLiteralExpr(Token, *SyntaxContext); } template <> ParsedExprSyntax Parser::parseExprSyntax() { auto Token = consumeTokenSyntax(); - return ParsedSyntaxRecorder::makeBooleanLiteralExpr(std::move(Token), *SyntaxContext); + return ParsedSyntaxRecorder::makeBooleanLiteralExpr(Token, *SyntaxContext); } template <> @@ -1341,11 +1341,11 @@ ParsedExprSyntax Parser::parseExprSyntax() { .fixItReplace(Tok.getLoc(), fixit); auto Token = consumeTokenSyntax(tok::kw___FILE__); - return ParsedSyntaxRecorder::makeUnknownExpr({&Token, 1}, *SyntaxContext); + return ParsedSyntaxRecorder::makeUnknownExpr({Token}, *SyntaxContext); } auto Token = consumeTokenSyntax(tok::pound_file); - return ParsedSyntaxRecorder::makePoundFileExpr(std::move(Token), *SyntaxContext); + return ParsedSyntaxRecorder::makePoundFileExpr(Token, *SyntaxContext); } template <> @@ -1356,12 +1356,12 @@ ParsedExprSyntax Parser::parseExprSyntax() { .fixItReplace(Tok.getLoc(), fixit); auto Token = consumeTokenSyntax(tok::kw___LINE__); - return ParsedSyntaxRecorder::makeUnknownExpr({&Token, 1}, *SyntaxContext); + return ParsedSyntaxRecorder::makeUnknownExpr({Token}, *SyntaxContext); } // FIXME: #line was renamed to #sourceLocation auto Token = consumeTokenSyntax(tok::pound_line); - return ParsedSyntaxRecorder::makePoundLineExpr(std::move(Token), *SyntaxContext); + return ParsedSyntaxRecorder::makePoundLineExpr(Token, *SyntaxContext); } template <> @@ -1372,11 +1372,11 @@ ParsedExprSyntax Parser::parseExprSyntax() { .fixItReplace(Tok.getLoc(), fixit); auto Token = consumeTokenSyntax(tok::kw___COLUMN__); - return ParsedSyntaxRecorder::makeUnknownExpr({&Token, 1}, *SyntaxContext); + return ParsedSyntaxRecorder::makeUnknownExpr({Token}, *SyntaxContext); } auto Token = consumeTokenSyntax(tok::pound_column); - return ParsedSyntaxRecorder::makePoundColumnExpr(std::move(Token), *SyntaxContext); + return ParsedSyntaxRecorder::makePoundColumnExpr(Token, *SyntaxContext); } template <> @@ -1387,11 +1387,11 @@ ParsedExprSyntax Parser::parseExprSyntax() { .fixItReplace(Tok.getLoc(), fixit); auto Token = consumeTokenSyntax(tok::kw___FUNCTION__); - return ParsedSyntaxRecorder::makeUnknownExpr({&Token, 1}, *SyntaxContext); + return ParsedSyntaxRecorder::makeUnknownExpr({Token}, *SyntaxContext); } auto Token = consumeTokenSyntax(tok::pound_function); - return ParsedSyntaxRecorder::makePoundFunctionExpr(std::move(Token), *SyntaxContext); + return ParsedSyntaxRecorder::makePoundFunctionExpr(Token, *SyntaxContext); } template <> @@ -1402,18 +1402,18 @@ ParsedExprSyntax Parser::parseExprSyntax() { .fixItReplace(Tok.getLoc(), fixit); auto Token = consumeTokenSyntax(tok::kw___DSO_HANDLE__); - return ParsedSyntaxRecorder::makeUnknownExpr({&Token, 1}, *SyntaxContext); + return ParsedSyntaxRecorder::makeUnknownExpr({Token}, *SyntaxContext); } auto Token = consumeTokenSyntax(tok::pound_dsohandle); - return ParsedSyntaxRecorder::makePoundDsohandleExpr(std::move(Token), *SyntaxContext); + return ParsedSyntaxRecorder::makePoundDsohandleExpr(Token, *SyntaxContext); } template ParserResult Parser::parseExprAST() { auto Loc = leadingTriviaLoc(); auto ParsedExpr = parseExprSyntax(); - SyntaxContext->addSyntax(std::move(ParsedExpr)); + SyntaxContext->addSyntax(ParsedExpr); // todo [gsoc]: improve this somehow if (SyntaxContext->isTopNode()) { auto Expr = SyntaxContext->topNode(); @@ -1519,9 +1519,9 @@ ParserResult Parser::parseExprPrimary(Diag<> ID, bool isExprBasic) { ParsedSyntaxRecorder::makeIdentifierPattern( SyntaxContext->popToken(), *SyntaxContext); ParsedExprSyntax ExprNode = - ParsedSyntaxRecorder::deferUnresolvedPatternExpr(std::move(PatternNode), + ParsedSyntaxRecorder::deferUnresolvedPatternExpr(PatternNode, *SyntaxContext); - SyntaxContext->addSyntax(std::move(ExprNode)); + SyntaxContext->addSyntax(ExprNode); return makeParserResult(new (Context) UnresolvedPatternExpr(pattern)); } diff --git a/lib/Parse/ParsePattern.cpp b/lib/Parse/ParsePattern.cpp index 3046decc2db7d..9cb81c42d6ee4 100644 --- a/lib/Parse/ParsePattern.cpp +++ b/lib/Parse/ParsePattern.cpp @@ -1169,7 +1169,6 @@ ParserResult Parser::parseMatchingPattern(bool isExprBasic) { // matching-pattern ::= expr // Fall back to expression parsing for ambiguous forms. Name lookup will // disambiguate. - DeferringContextRAII Deferring(*SyntaxContext); ParserResult subExpr = parseExprImpl(diag::expected_pattern, isExprBasic); ParserStatus status = subExpr; diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 69f9c38c66134..ffa1edf33d6b6 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -181,8 +181,8 @@ Parser::TypeResult Parser::parseTypeSimple(Diag<> MessageID, // Eat the code completion token because we handled it. auto CCTok = consumeTokenSyntax(tok::code_complete); ParsedTypeSyntax ty = - ParsedSyntaxRecorder::makeUnknownType({&CCTok, 1}, *SyntaxContext); - return makeParsedCodeCompletion(std::move(ty)); + ParsedSyntaxRecorder::makeUnknownType({CCTok}, *SyntaxContext); + return makeParsedCodeCompletion(ty); } case tok::l_square: Result = parseTypeCollection(); @@ -203,10 +203,9 @@ Parser::TypeResult Parser::parseTypeSimple(Diag<> MessageID, } if (Tok.isKeyword() && !Tok.isAtStartOfLine()) { - auto token = consumeTokenSyntax(); ParsedTypeSyntax ty = ParsedSyntaxRecorder::makeUnknownType( - {&token, 1}, *SyntaxContext); - return makeParsedError(std::move(ty)); + {consumeTokenSyntax()}, *SyntaxContext); + return makeParsedError(ty); } checkForInputIncomplete(); @@ -257,7 +256,7 @@ Parser::parseTypeSyntax(Diag<> messageID, bool HandleCodeCompletion, auto tyR = parseType(messageID, HandleCodeCompletion, IsSILFuncDecl); if (auto ty = SyntaxContext->popIf()) { Generator.addType(tyR.getPtrOrNull(), loc); - return makeParsedResult(std::move(*ty), tyR.getStatus()); + return makeParsedResult(*ty, tyR.getStatus()); } return tyR.getStatus(); } @@ -270,7 +269,7 @@ Parser::TypeASTResult Parser::parseSILBoxType(GenericParamList *generics, const TypeAttributes &attrs, Optional &GenericsScope) { auto LBraceLoc = consumeToken(tok::l_brace); - + SmallVector Fields; if (!Tok.is(tok::r_brace)) { for (;;) { @@ -284,30 +283,30 @@ Parser::TypeASTResult Parser::parseSILBoxType(GenericParamList *generics, return makeParserError(); } SourceLoc VarOrLetLoc = consumeToken(); - + auto fieldTy = parseType(); if (!fieldTy.getPtrOrNull()) return makeParserError(); Fields.push_back({VarOrLetLoc, Mutable, fieldTy.get()}); - + if (consumeIf(tok::comma)) continue; - + break; } } - + if (!Tok.is(tok::r_brace)) { diagnose(Tok, diag::sil_box_expected_r_brace); return makeParserError(); } - + auto RBraceLoc = consumeToken(tok::r_brace); - + // The generic arguments are taken from the enclosing scope. Pop the // box layout's scope now. GenericsScope.reset(); - + SourceLoc LAngleLoc, RAngleLoc; SmallVector Args; if (Tok.isContextualPunctuator("<")) { @@ -325,7 +324,7 @@ Parser::TypeASTResult Parser::parseSILBoxType(GenericParamList *generics, diagnose(Tok, diag::sil_box_expected_r_angle); return makeParserError(); } - + RAngleLoc = consumeToken(); } @@ -371,7 +370,7 @@ Parser::TypeASTResult Parser::parseType(Diag<> MessageID, GenericsScope.emplace(this, ScopeKind::Generics); generics = maybeParseGenericParams().getPtrOrNull(); } - + // In SIL mode, parse box types { ... }. if (isInSILMode() && Tok.is(tok::l_brace)) { auto SILBoxType = parseSILBoxType(generics, attrs, GenericsScope); @@ -423,15 +422,16 @@ Parser::TypeASTResult Parser::parseType(Diag<> MessageID, parseType(diag::expected_type_function_result); auto SecondTy = SyntaxContext->popIf(); if (SecondHalf.isParseError()) { - SyntaxContext->addSyntax(std::move(InputNode)); + SyntaxContext->addSyntax(InputNode); if (Throws) - SyntaxContext->addSyntax(std::move(*Throws)); - SyntaxContext->addSyntax(std::move(Arrow)); + SyntaxContext->addSyntax(*Throws); + SyntaxContext->addSyntax(Arrow); if (SecondTy) - SyntaxContext->addSyntax(std::move(*SecondTy)); + SyntaxContext->addSyntax(*SecondTy); if (SecondHalf.hasCodeCompletion()) return makeParserCodeCompletionResult(); - return makeParserErrorResult(); + if (SecondHalf.isNull()) + return nullptr; } ParsedFunctionTypeSyntaxBuilder Builder(*SyntaxContext); @@ -442,9 +442,9 @@ Parser::TypeASTResult Parser::parseType(Diag<> MessageID, auto Arguments = TupleTypeNode->getDeferredElements(); auto RightParen = TupleTypeNode->getDeferredRightParen(); Builder - .useLeftParen(std::move(LeftParen)) - .useArguments(std::move(Arguments)) - .useRightParen(std::move(RightParen)); + .useLeftParen(LeftParen) + .useArguments(Arguments) + .useRightParen(RightParen); } else { // FIXME(syntaxparse): Extract 'Void' text from recoreded node. if (const auto Void = dyn_cast(tyR)) @@ -460,13 +460,14 @@ Parser::TypeASTResult Parser::parseType(Diag<> MessageID, .fixItInsertAfter(tyR->getEndLoc(), ")"); } Builder.addArgumentsMember(ParsedSyntaxRecorder::makeTupleTypeElement( - std::move(InputNode), /*TrailingComma=*/None, *SyntaxContext)); + InputNode, /*TrailingComma=*/None, *SyntaxContext)); } + Builder.useReturnType(*SecondTy); if (Throws) - Builder.useThrowsOrRethrowsKeyword(std::move(*Throws)); - Builder.useArrow(std::move(Arrow)); - Builder.useReturnType(std::move(*SecondTy)); + Builder.useThrowsOrRethrowsKeyword(*Throws); + Builder.useArrow(Arrow); + Builder.useReturnType(*SecondTy); SyntaxContext->addSyntax(Builder.build()); @@ -627,7 +628,7 @@ Parser::parseGenericArgumentsAST(SmallVectorImpl &ArgsAST, } /// parseTypeIdentifier -/// +/// /// type-identifier: /// identifier generic-args? ('.' identifier generic-args?)* /// @@ -641,10 +642,9 @@ Parser::TypeResult Parser::parseTypeIdentifier() { if (CodeCompletion) CodeCompletion->completeTypeSimpleBeginning(); - auto CCTok = consumeTokenSyntax(tok::code_complete); auto ty = ParsedSyntaxRecorder::makeUnknownType( - {&CCTok, 1}, *SyntaxContext); - return makeParsedCodeCompletion(std::move(ty)); + {consumeTokenSyntax(tok::code_complete)}, *SyntaxContext); + return makeParsedCodeCompletion(ty); } diagnose(Tok, diag::expected_identifier_for_type); @@ -652,10 +652,9 @@ Parser::TypeResult Parser::parseTypeIdentifier() { // If there is a keyword at the start of a new line, we won't want to // skip it as a recovery but rather keep it. if (Tok.isKeyword() && !Tok.isAtStartOfLine()) { - auto kwTok = consumeTokenSyntax(); ParsedTypeSyntax ty = ParsedSyntaxRecorder::makeUnknownType( - {&kwTok, 1}, *SyntaxContext); - return makeParsedError(std::move(ty)); + {consumeTokenSyntax()}, *SyntaxContext); + return makeParsedError(ty); } return makeParsedError(); @@ -677,42 +676,42 @@ Parser::TypeResult Parser::parseTypeIdentifier() { // FIXME: offer a fixit: 'self' -> 'Self' Identifier = parseIdentifierSyntax(diag::expected_identifier_in_dotted_type); + if (!Identifier) { + Status.setIsParseError(); + if (Base) + Junk.push_back(*Base); + if (Period) + Junk.push_back(*Period); + } } if (Identifier) { Optional GenericArgs; - + if (startsWithLess(Tok)) { SmallVector GenericArgsAST; SourceLoc LAngleLoc, RAngleLoc; auto GenericArgsResult = parseGenericArgumentClauseSyntax(); if (GenericArgsResult.isError()) { if (Base) - Junk.push_back(std::move(*Base)); + Junk.push_back(*Base); if (Period) - Junk.push_back(std::move(*Period)); - Junk.push_back(std::move(*Identifier)); + Junk.push_back(*Period); + Junk.push_back(*Identifier); if (!GenericArgsResult.isNull()) Junk.push_back(GenericArgsResult.get()); auto ty = ParsedSyntaxRecorder::makeUnknownType(Junk, *SyntaxContext); - return makeParsedResult(std::move(ty), GenericArgsResult.getStatus()); + return makeParsedResult(ty, GenericArgsResult.getStatus()); } GenericArgs = GenericArgsResult.get(); } if (!Base) Base = ParsedSyntaxRecorder::makeSimpleTypeIdentifier( - std::move(*Identifier), std::move(GenericArgs), *SyntaxContext); + *Identifier, GenericArgs, *SyntaxContext); else Base = ParsedSyntaxRecorder::makeMemberTypeIdentifier( - std::move(*Base), std::move(*Period), std::move(*Identifier), - std::move(GenericArgs), *SyntaxContext); - } else { - Status.setIsParseError(); - if (Base) - Junk.push_back(std::move(*Base)); - if (Period) - Junk.push_back(std::move(*Period)); + *Base, *Period, *Identifier, GenericArgs, *SyntaxContext); } // Treat 'Foo.' as an attempt to write a dotted type @@ -739,16 +738,17 @@ Parser::TypeResult Parser::parseTypeIdentifier() { IdentTypeRepr *ITR = nullptr; if (Base) { - SyntaxContext->addSyntax(std::move(*Base)); + SyntaxContext->addSyntax(*Base); auto T = SyntaxContext->topNode(); - Junk.push_back(*SyntaxContext->popIf()); + SyntaxContext->popIf(); ITR = dyn_cast(Generator.generate(T, BaseLoc)); + Junk.push_back(*Base); } if (Tok.isNot(tok::code_complete)) { // We have a dot. auto Dot = consumeTokenSyntax(); - Junk.push_back(std::move(Dot)); + Junk.push_back(Dot); if (CodeCompletion) CodeCompletion->completeTypeIdentifierWithDot(ITR); } else { @@ -758,15 +758,15 @@ Parser::TypeResult Parser::parseTypeIdentifier() { // Eat the code completion token because we handled it. Junk.push_back(consumeTokenSyntax(tok::code_complete)); auto ty = ParsedSyntaxRecorder::makeUnknownType(Junk, *SyntaxContext); - return makeParsedCodeCompletion(std::move(ty)); + return makeParsedCodeCompletion(ty); } - + if (Status.isError()) { auto ty = ParsedSyntaxRecorder::makeUnknownType(Junk, *SyntaxContext); - return makeParsedError(std::move(ty)); + return makeParsedError(ty); } - return makeParsedResult(std::move(*Base)); + return makeParsedResult(*Base); } Parser::TypeASTResult @@ -803,11 +803,9 @@ Parser::parseTypeSimpleOrComposition(Diag<> MessageID, FirstSome = consumeTokenSyntax(); } - auto ApplySome = [this](ParsedTypeSyntax Type, - Optional Some) { - return Some ? ParsedSyntaxRecorder::makeSomeType( - std::move(*Some), std::move(Type), *SyntaxContext) - : std::move(Type); + auto ApplySome = [this](ParsedTypeSyntax Type, Optional Some) { + return Some ? ParsedSyntaxRecorder::makeSomeType(*Some, Type, *SyntaxContext) + : Type; }; // Parse the first type @@ -819,15 +817,14 @@ Parser::parseTypeSimpleOrComposition(Diag<> MessageID, auto FirstType = FirstTypeResult.get(); if (!Tok.isContextualPunctuator("&")) - return makeParsedResult( - ApplySome(std::move(FirstType), std::move(FirstSome))); + return makeParsedResult(ApplySome(FirstType, FirstSome)); SmallVector Elements; - + Optional Ampersand = consumeTokenSyntax(); auto FirstElement = ParsedSyntaxRecorder::makeCompositionTypeElement( - std::move(FirstType), std::move(*Ampersand), *SyntaxContext); - Elements.push_back(std::move(FirstElement)); + FirstType, *Ampersand, *SyntaxContext); + Elements.push_back(FirstElement); ParserStatus Status; @@ -851,46 +848,45 @@ Parser::parseTypeSimpleOrComposition(Diag<> MessageID, SmallVector nodes; if (FirstSome) - nodes.push_back(std::move(*FirstSome)); - std::move(Elements.begin(), Elements.end(), std::back_inserter(nodes)); + nodes.push_back(*FirstSome); + nodes.append(Elements.begin(), Elements.end()); if (NextSome) - nodes.push_back(std::move(*NextSome)); + nodes.push_back(*NextSome); nodes.push_back(NextTypeResult.get()); auto ty = ParsedSyntaxRecorder::makeUnknownType(nodes, *SyntaxContext); - return makeParsedResult(std::move(ty), Status); + return makeParsedResult(ty, Status); } - auto NextType = ApplySome(NextTypeResult.get(), std::move(NextSome)); - Ampersand = Tok.isContextualPunctuator("&") - ? consumeTokenSyntax() + auto NextType = ApplySome(NextTypeResult.get(), NextSome); + Ampersand = Tok.isContextualPunctuator("&") + ? consumeTokenSyntax() : llvm::Optional(); auto NextElement = ParsedSyntaxRecorder::makeCompositionTypeElement( - std::move(NextType), std::move(Ampersand), *SyntaxContext); - Elements.push_back(std::move(NextElement)); + NextType, Ampersand, *SyntaxContext); + Elements.push_back(NextElement); } while (Ampersand); auto ElementList = ParsedSyntaxRecorder::makeCompositionTypeElementList( Elements, *SyntaxContext); - auto Composition = ParsedSyntaxRecorder::makeCompositionType( - std::move(ElementList), *SyntaxContext); - return makeParsedResult( - ApplySome(std::move(Composition), std::move(FirstSome)), Status); + auto Composition = + ParsedSyntaxRecorder::makeCompositionType(ElementList, *SyntaxContext); + return makeParsedResult(ApplySome(Composition, FirstSome), Status); } Parser::TypeASTResult Parser::parseAnyTypeAST() { auto AnyLoc = leadingTriviaLoc(); auto ParsedAny = parseAnyType().get(); - SyntaxContext->addSyntax(std::move(ParsedAny)); + SyntaxContext->addSyntax(ParsedAny); auto Any = SyntaxContext->topNode(); return makeParserResult(Generator.generate(Any, AnyLoc)); } Parser::TypeResult Parser::parseAnyType() { auto Any = consumeTokenSyntax(tok::kw_Any); - auto Type = ParsedSyntaxRecorder::makeSimpleTypeIdentifier( - std::move(Any), llvm::None, *SyntaxContext); - return makeParsedResult(std::move(Type)); + auto Type = ParsedSyntaxRecorder::makeSimpleTypeIdentifier(Any, llvm::None, + *SyntaxContext); + return makeParsedResult(Type); } /// parseOldStyleProtocolComposition @@ -913,8 +909,8 @@ Parser::TypeResult Parser::parseOldStyleProtocolComposition() { auto LAngleLoc = Tok.getLoc(); auto LAngle = consumeStartingLessSyntax(); - Junk.push_back(Protocol.copyDeferred()); - Junk.push_back(LAngle.copyDeferred()); + Junk.push_back(Protocol); + Junk.push_back(LAngle); // Parse the type-composition-list. ParserStatus Status; @@ -928,13 +924,13 @@ Parser::TypeResult Parser::parseOldStyleProtocolComposition() { Status |= TypeResult.getStatus(); if (TypeResult.isSuccess()) { auto Type = TypeResult.get(); - Junk.push_back(Type.copyDeferred()); + Junk.push_back(Type); if (!IsAny) - Protocols.push_back(std::move(Type)); + Protocols.push_back(Type); } Comma = consumeTokenSyntaxIf(tok::comma); if (Comma) - Junk.push_back(Comma->copyDeferred()); + Junk.push_back(*Comma); } while (Comma); } @@ -943,7 +939,7 @@ Parser::TypeResult Parser::parseOldStyleProtocolComposition() { if (startsWithGreater(Tok)) { RAngleLoc = Tok.getLoc(); auto RAngle = consumeStartingGreaterSyntax(); - Junk.push_back(RAngle.copyDeferred()); + Junk.push_back(RAngle); } else { if (Status.isSuccess()) { diagnose(Tok, diag::expected_rangle_protocol); @@ -955,7 +951,7 @@ Parser::TypeResult Parser::parseOldStyleProtocolComposition() { // Skip until we hit the '>'. skipUntilGreaterInTypeListSyntax(RAngleJunk, /*protocolComposition=*/true); for (auto &&Piece : RAngleJunk) - Junk.push_back(Piece.copyDeferred()); + Junk.push_back(Piece); } if (Status.isSuccess()) { @@ -963,7 +959,7 @@ Parser::TypeResult Parser::parseOldStyleProtocolComposition() { if (Protocols.empty()) { replacement = "Any"; } else { - auto extractText = [&](ParsedTypeSyntax &Type) -> StringRef { + auto extractText = [&](ParsedTypeSyntax Type) -> StringRef { auto SourceRange = Type.getRaw().getDeferredRange(); return SourceMgr.extractText(SourceRange); }; @@ -979,7 +975,7 @@ Parser::TypeResult Parser::parseOldStyleProtocolComposition() { // Need parenthesis if the next token looks like postfix TypeRepr. // i.e. '?', '!', '.Type', '.Protocol' bool needParen = false; - needParen |= !Tok.isAtStartOfLine() && + needParen |= !Tok.isAtStartOfLine() && (isOptionalToken(Tok) || isImplicitlyUnwrappedOptionalToken(Tok)); needParen |= Tok.isAny(tok::period, tok::period_prefix); if (needParen) { @@ -1005,7 +1001,7 @@ Parser::TypeResult Parser::parseOldStyleProtocolComposition() { } auto Unknown = ParsedSyntaxRecorder::makeUnknownType(Junk, *SyntaxContext); - return makeParsedResult(std::move(Unknown)); + return makeParsedResult(Unknown); } /// parseTypeTupleBody @@ -1026,14 +1022,15 @@ Parser::TypeResult Parser::parseTypeTupleBody() { return makeParsedError(); SmallVector Junk; - + auto LParenLoc = Tok.getLoc(); auto LParen = consumeTokenSyntax(tok::l_paren); - Junk.push_back(LParen.copyDeferred()); + Junk.push_back(LParen); SmallVector Elements; SmallVector, 4> ElementsLoc; + Optional FirstEllipsis; SourceLoc FirstEllipsisLoc; Optional Comma; @@ -1058,7 +1055,7 @@ Parser::TypeResult Parser::parseTypeTupleBody() { InOut = consumeTokenSyntax(tok::kw_inout); IsInOutObsoleted = true; - LocalJunk.push_back(InOut->copyDeferred()); + LocalJunk.push_back(*InOut); } // If the label is "some", this could end up being an opaque type @@ -1081,18 +1078,18 @@ Parser::TypeResult Parser::parseTypeTupleBody() { // Consume a name. NameLoc = Tok.getLoc(); Name = consumeArgumentLabelSyntax(); - LocalJunk.push_back(Name->copyDeferred()); + LocalJunk.push_back(*Name); // If there is a second name, consume it as well. if (Tok.canBeArgumentLabel()) { SecondNameLoc = Tok.getLoc(); SecondName = consumeArgumentLabelSyntax(); - LocalJunk.push_back(SecondName->copyDeferred()); + LocalJunk.push_back(*SecondName); } // Consume the ':'. if ((Colon = consumeTokenSyntaxIf(tok::colon))) { - LocalJunk.push_back(Colon->copyDeferred()); + LocalJunk.push_back(*Colon); // If we succeed, then we successfully parsed a label. if (Backtracking) Backtracking->cancelBacktrack(); @@ -1113,22 +1110,19 @@ Parser::TypeResult Parser::parseTypeTupleBody() { // Parse the type annotation. auto TypeLoc = Tok.getLoc(); - auto ty = parseTypeSyntax(diag::expected_type); - if (ty.hasCodeCompletion() || ty.isNull()) { - std::move(LocalJunk.begin(), LocalJunk.end(), std::back_inserter(Junk)); - if (!ty.isNull()) - Junk.push_back(ty.get()); + auto Type = parseTypeSyntax(diag::expected_type); + if (Type.hasCodeCompletion() || Type.isNull()) { + Junk.append(LocalJunk.begin(), LocalJunk.end()); + if (!Type.isNull()) + Junk.push_back(Type.get()); skipListUntilDeclRBraceSyntax(Junk, LParenLoc, tok::r_paren, tok::comma); - return ty.getStatus(); + return Type.getStatus(); } if (IsInOutObsoleted) { bool IsTypeAlreadyAttributed = false; - if (auto AttributedType = ty.getAs()) { - IsTypeAlreadyAttributed = - AttributedType->getDeferredSpecifier().hasValue(); - ty = makeParsedResult(std::move(*AttributedType), ty.getStatus()); - } + if (auto AttributedType = Type.get().getAs()) + IsTypeAlreadyAttributed = AttributedType->getDeferredSpecifier().hasValue(); if (IsTypeAlreadyAttributed) { // If the parsed type is already attributed, suggest removing `inout`. @@ -1146,7 +1140,8 @@ Parser::TypeResult Parser::parseTypeTupleBody() { Tok.setKind(tok::ellipsis); auto ElementEllipsisLoc = Tok.getLoc(); ElementEllipsis = consumeTokenSyntax(); - if (!FirstEllipsisLoc.isValid()) { + if (!FirstEllipsis) { + FirstEllipsis = ElementEllipsis; FirstEllipsisLoc = ElementEllipsisLoc; } else { diagnose(ElementEllipsisLoc, diag::multiple_ellipsis_in_tuple) @@ -1165,20 +1160,19 @@ Parser::TypeResult Parser::parseTypeTupleBody() { if (Init.isNonNull()) InFlight.fixItRemove(SourceRange(EqualLoc, Init.get()->getEndLoc())); auto Expr = *SyntaxContext->popIf(); - Initializer = ParsedSyntaxRecorder::makeInitializerClause( - std::move(*Equal), std::move(Expr), *SyntaxContext); + Initializer = ParsedSyntaxRecorder::makeInitializerClause(*Equal, Expr, + *SyntaxContext); } Comma = consumeTokenSyntaxIf(tok::comma); auto Element = ParsedSyntaxRecorder::makeTupleTypeElement( - std::move(InOut), std::move(Name), std::move(SecondName), - std::move(Colon), ty.get(), std::move(ElementEllipsis), - std::move(Initializer), std::move(Comma), *SyntaxContext); + InOut, Name, SecondName, Colon, Type.get(), ElementEllipsis, Initializer, + Comma, *SyntaxContext); - Junk.push_back(Element.copyDeferred()); + Junk.push_back(Element); - Elements.push_back(std::move(Element)); + Elements.push_back(Element); ElementsLoc.emplace_back(NameLoc, SecondNameLoc, TypeLoc); return makeParserSuccess(); @@ -1186,9 +1180,15 @@ Parser::TypeResult Parser::parseTypeTupleBody() { if (!Status.isSuccess()) { auto ty = ParsedSyntaxRecorder::makeUnknownType(Junk, *SyntaxContext); - return makeParsedResult(std::move(ty), Status); + return makeParsedResult(ty, Status); } + auto ElementList = + ParsedSyntaxRecorder::makeTupleTypeElementList(Elements, *SyntaxContext); + + auto TupleType = ParsedSyntaxRecorder::makeTupleType(LParen, ElementList, + *RParen, *SyntaxContext); + bool IsFunctionType = Tok.isAny(tok::arrow, tok::kw_throws, tok::kw_rethrows); auto GetNameText = [this](Optional Name) { @@ -1201,7 +1201,7 @@ Parser::TypeResult Parser::parseTypeTupleBody() { if (!IsFunctionType) { for (unsigned i = 0; i < Elements.size(); i++) { // true tuples have labels - auto &Element = Elements[i]; + auto Element = Elements[i]; SourceLoc NameLoc, SecondNameLoc, TypeLoc; std::tie(NameLoc, SecondNameLoc, TypeLoc) = ElementsLoc[i]; // If there were two names, complain. @@ -1223,7 +1223,7 @@ Parser::TypeResult Parser::parseTypeTupleBody() { for (unsigned i = 0; i < Elements.size(); i++) { // If there was a first name, complain; arguments in function types are // always unlabeled. - auto &Element = Elements[i]; + auto Element = Elements[i]; SourceLoc NameLoc, SecondNameLoc, TypeLoc; std::tie(NameLoc, SecondNameLoc, TypeLoc) = ElementsLoc[i]; if (NameLoc.isValid()) { @@ -1244,14 +1244,7 @@ Parser::TypeResult Parser::parseTypeTupleBody() { } } - auto ElementList = - ParsedSyntaxRecorder::makeTupleTypeElementList(Elements, *SyntaxContext); - - auto TupleType = ParsedSyntaxRecorder::makeTupleType( - std::move(LParen), std::move(ElementList), std::move(*RParen), - *SyntaxContext); - - return makeParsedResult(std::move(TupleType)); + return makeParsedResult(TupleType); } /// parseTypeArray - Parse the type-array production, given that we @@ -1285,9 +1278,9 @@ Parser::TypeResult Parser::parseTypeArray(ParsedTypeSyntax Base, } ParsedArrayTypeSyntaxBuilder builder(*SyntaxContext); - builder.useElementType(std::move(Base)); + builder.useElementType(Base); if (RSquare) - builder.useRightSquareBracket(std::move(*RSquare)); + builder.useRightSquareBracket(*RSquare); return makeParsedError(builder.build()); } @@ -1326,37 +1319,35 @@ Parser::TypeResult Parser::parseTypeCollection() { if (!Status.isSuccess()) { SmallVector Pieces; - Pieces.push_back(std::move(LSquare)); + Pieces.push_back(LSquare); if (ElementType) - Pieces.push_back(std::move(*ElementType)); + Pieces.push_back(*ElementType); if (Colon) - Pieces.push_back(std::move(*Colon)); + Pieces.push_back(*Colon); if (ValueType) - Pieces.push_back(std::move(*ValueType)); + Pieces.push_back(*ValueType); if (RSquare) - Pieces.push_back(std::move(*RSquare)); + Pieces.push_back(*RSquare); ParsedTypeSyntax ty = ParsedSyntaxRecorder::makeUnknownType(Pieces, *SyntaxContext); - return makeParsedResult(std::move(ty), Status); + return makeParsedResult(ty, Status); } if (Colon) return makeParsedResult(ParsedSyntaxRecorder::makeDictionaryType( - std::move(LSquare), std::move(*ElementType), std::move(*Colon), - std::move(*ValueType), std::move(*RSquare), *SyntaxContext)); + LSquare, *ElementType, *Colon, *ValueType, *RSquare, *SyntaxContext)); return makeParsedResult(ParsedSyntaxRecorder::makeArrayType( - std::move(LSquare), std::move(*ElementType), std::move(*RSquare), - *SyntaxContext)); + LSquare, *ElementType, *RSquare, *SyntaxContext)); } Parser::TypeResult Parser::parseMetatypeType(ParsedTypeSyntax Base) { auto Period = consumeTokenSyntax(); // tok::period or tok::period_prefix auto Keyword = consumeTokenSyntax(tok::identifier); // "Type" or "Protocol" auto MetatypeType = ParsedSyntaxRecorder::makeMetatypeType( - std::move(Base), std::move(Period), std::move(Keyword), *SyntaxContext); - return makeParsedResult(std::move(MetatypeType)); + Base, Period, Keyword, *SyntaxContext); + return makeParsedResult(MetatypeType); } bool Parser::isOptionalToken(const Token &T) const { @@ -1412,17 +1403,17 @@ SourceLoc Parser::consumeImplicitlyUnwrappedOptionalToken() { Parser::TypeResult Parser::parseOptionalType(ParsedTypeSyntax Base) { auto Question = consumeOptionalTokenSyntax(); - auto Optional = ParsedSyntaxRecorder::makeOptionalType( - std::move(Base), std::move(Question), *SyntaxContext); - return makeParsedResult(std::move(Optional)); + auto Optional = + ParsedSyntaxRecorder::makeOptionalType(Base, Question, *SyntaxContext); + return makeParsedResult(Optional); } Parser::TypeResult Parser::parseImplicitlyUnwrappedOptionalType(ParsedTypeSyntax Base) { auto Exclamation = consumeImplicitlyUnwrappedOptionalTokenSyntax(); auto Unwrapped = ParsedSyntaxRecorder::makeImplicitlyUnwrappedOptionalType( - std::move(Base), std::move(Exclamation), *SyntaxContext); - return makeParsedResult(std::move(Unwrapped)); + Base, Exclamation, *SyntaxContext); + return makeParsedResult(Unwrapped); } //===----------------------------------------------------------------------===// diff --git a/lib/Parse/ParsedRawSyntaxNode.cpp b/lib/Parse/ParsedRawSyntaxNode.cpp index 608381d236e57..3ae3834b25841 100644 --- a/lib/Parse/ParsedRawSyntaxNode.cpp +++ b/lib/Parse/ParsedRawSyntaxNode.cpp @@ -19,20 +19,15 @@ using namespace llvm; ParsedRawSyntaxNode ParsedRawSyntaxNode::makeDeferred(SyntaxKind k, - MutableArrayRef deferredNodes, + ArrayRef deferredNodes, SyntaxParsingContext &ctx) { if (deferredNodes.empty()) { return ParsedRawSyntaxNode(k, {}); } ParsedRawSyntaxNode *newPtr = ctx.getScratchAlloc().Allocate(deferredNodes.size()); - - // uninitialized move; - auto ptr = newPtr; - for (auto &node : deferredNodes) - :: new (static_cast(ptr++)) ParsedRawSyntaxNode(std::move(node)); - - return ParsedRawSyntaxNode(k, makeMutableArrayRef(newPtr, deferredNodes.size())); + std::uninitialized_copy(deferredNodes.begin(), deferredNodes.end(), newPtr); + return ParsedRawSyntaxNode(k, makeArrayRef(newPtr, deferredNodes.size())); } ParsedRawSyntaxNode @@ -64,13 +59,13 @@ void ParsedRawSyntaxNode::dump(llvm::raw_ostream &OS, unsigned Indent) const { for (decltype(Indent) i = 0; i < Indent; ++i) OS << ' '; OS << '('; + dumpSyntaxKind(OS, getKind()); switch (DK) { case DataKind::Null: OS << ""; break; case DataKind::Recorded: - dumpSyntaxKind(OS, getKind()); OS << " [recorded] "; if (isToken()) { dumpTokenKind(OS, getTokenKind()); @@ -79,7 +74,6 @@ void ParsedRawSyntaxNode::dump(llvm::raw_ostream &OS, unsigned Indent) const { } break; case DataKind::DeferredLayout: - dumpSyntaxKind(OS, getKind()); OS << " [deferred]"; for (const auto &child : getDeferredChildren()) { OS << "\n"; @@ -87,7 +81,6 @@ void ParsedRawSyntaxNode::dump(llvm::raw_ostream &OS, unsigned Indent) const { } break; case DataKind::DeferredToken: - dumpSyntaxKind(OS, getKind()); OS << " [deferred] "; dumpTokenKind(OS, getTokenKind()); break; diff --git a/lib/Parse/ParsedRawSyntaxRecorder.cpp b/lib/Parse/ParsedRawSyntaxRecorder.cpp index 09e81834ded7e..1c064fb682670 100644 --- a/lib/Parse/ParsedRawSyntaxRecorder.cpp +++ b/lib/Parse/ParsedRawSyntaxRecorder.cpp @@ -57,8 +57,9 @@ ParsedRawSyntaxRecorder::recordMissingToken(tok tokenKind, SourceLoc loc) { } static ParsedRawSyntaxNode -getRecordedNode(ParsedRawSyntaxNode node, ParsedRawSyntaxRecorder &rec) { - assert(!node.isNull() && !node.isRecorded()); +getRecordedNode(const ParsedRawSyntaxNode &node, ParsedRawSyntaxRecorder &rec) { + if (node.isNull() || node.isRecorded()) + return node; if (node.isDeferredLayout()) return rec.recordRawSyntax(node.getKind(), node.getDeferredChildren()); assert(node.isDeferredToken()); @@ -73,29 +74,24 @@ getRecordedNode(ParsedRawSyntaxNode node, ParsedRawSyntaxRecorder &rec) { ParsedRawSyntaxNode ParsedRawSyntaxRecorder::recordRawSyntax(SyntaxKind kind, - MutableArrayRef elements) { + ArrayRef elements) { CharSourceRange range; SmallVector subnodes; if (!elements.empty()) { SourceLoc offset; unsigned length = 0; - for (auto &subnode : elements) { - CharSourceRange localRange; + for (const auto &elem : elements) { + auto subnode = getRecordedNode(elem, *this); if (subnode.isNull()) { subnodes.push_back(nullptr); - } else if (subnode.isRecorded()) { - localRange = subnode.getRecordedRange(); - subnodes.push_back(subnode.takeOpaqueNode()); } else { - auto recorded = getRecordedNode(subnode.copyDeferred(), *this); - localRange = recorded.getRecordedRange(); - subnodes.push_back(recorded.takeOpaqueNode()); - } - - if (localRange.isValid()) { - if (offset.isInvalid()) - offset = localRange.getStart(); - length += localRange.getByteLength(); + subnodes.push_back(subnode.getOpaqueNode()); + auto range = subnode.getRecordedRange(); + if (range.isValid()) { + if (offset.isInvalid()) + offset = range.getStart(); + length += subnode.getRecordedRange().getByteLength(); + } } } range = CharSourceRange{offset, length}; @@ -112,10 +108,6 @@ ParsedRawSyntaxRecorder::recordEmptyRawSyntaxCollection(SyntaxKind kind, return ParsedRawSyntaxNode{kind, tok::unknown, range, n}; } -void ParsedRawSyntaxRecorder::discardRecordedNode(ParsedRawSyntaxNode &node) { - SPActions->discardRecordedNode(node.takeOpaqueNode()); -} - ParsedRawSyntaxNode ParsedRawSyntaxRecorder::lookupNode(size_t lexerOffset, SourceLoc loc, SyntaxKind kind) { diff --git a/lib/Parse/ParsedSyntaxBuilders.cpp.gyb b/lib/Parse/ParsedSyntaxBuilders.cpp.gyb index 9ab3964f2b2cb..a8e662639c465 100644 --- a/lib/Parse/ParsedSyntaxBuilders.cpp.gyb +++ b/lib/Parse/ParsedSyntaxBuilders.cpp.gyb @@ -43,14 +43,14 @@ Parsed${node.name}Builder::use${child.name}(Parsed${child.type_name} ${child.nam assert(${child_elt_name}s.empty() && "use either 'use' function or 'add', not both"); % end Layout[cursorIndex(${node.name}::Cursor::${child.name})] = - ${child.name}.takeRaw(); + ${child.name}.getRaw(); return *this; } % if child_elt: Parsed${node.name}Builder & Parsed${node.name}Builder::add${child_elt_name}(Parsed${child_elt_type} ${child_elt}) { assert(Layout[cursorIndex(${node.name}::Cursor::${child.name})].isNull() && "use either 'use' function or 'add', not both"); - ${child_elt_name}s.push_back(${child_elt}.takeRaw()); + ${child_elt_name}s.push_back(std::move(${child_elt}.getRaw())); return *this; } % end diff --git a/lib/Parse/ParsedSyntaxNodes.cpp.gyb b/lib/Parse/ParsedSyntaxNodes.cpp.gyb index e3bb56c91812e..0f7a13c109043 100644 --- a/lib/Parse/ParsedSyntaxNodes.cpp.gyb +++ b/lib/Parse/ParsedSyntaxNodes.cpp.gyb @@ -28,14 +28,14 @@ using namespace swift::syntax; % if child.is_optional: Optional Parsed${node.name}::getDeferred${child.name}() { - auto &RawChild = getRaw().getDeferredChildren()[${node.name}::Cursor::${child.name}]; + auto RawChild = getRaw().getDeferredChildren()[${node.name}::Cursor::${child.name}]; if (RawChild.isNull()) return None; - return Parsed${child.type_name} {RawChild.copyDeferred()}; + return Parsed${child.type_name} {RawChild}; } % else: Parsed${child.type_name} Parsed${node.name}::getDeferred${child.name}() { - return Parsed${child.type_name} {getRaw().getDeferredChildren()[${node.name}::Cursor::${child.name}].copyDeferred()}; + return Parsed${child.type_name} {getRaw().getDeferredChildren()[${node.name}::Cursor::${child.name}]}; } % end diff --git a/lib/Parse/ParsedSyntaxRecorder.cpp.gyb b/lib/Parse/ParsedSyntaxRecorder.cpp.gyb index b305e25e7cc8f..7ab92a4ffa509 100644 --- a/lib/Parse/ParsedSyntaxRecorder.cpp.gyb +++ b/lib/Parse/ParsedSyntaxRecorder.cpp.gyb @@ -26,8 +26,8 @@ using namespace swift; using namespace swift::syntax; bool ParsedSyntaxRecorder::formExactLayoutFor(syntax::SyntaxKind Kind, - MutableArrayRef Elements, - function_ref)> receiver) { + ArrayRef Elements, + function_ref)> receiver) { switch (Kind) { % for node in SYNTAX_NODES: case SyntaxKind::${node.syntax_kind}: { @@ -42,23 +42,16 @@ bool ParsedSyntaxRecorder::formExactLayoutFor(syntax::SyntaxKind Kind, % if child.is_optional: Layout[${child_idx}] = ParsedRawSyntaxNode::null(); % else: - for (unsigned i = 0, e = ${child_count}; i != e; ++i) - Layout[i].reset(); return false; % end } else { - Layout[${child_idx}] = Elements[I].unsafeCopy(); + Layout[${child_idx}] = Elements[I]; ++I; } % end - if (I != Elements.size()) { - for (unsigned i = 0, e = ${child_count}; i != e; ++i) - Layout[i].reset(); + if (I != Elements.size()) return false; - } receiver(Kind, Layout); - for (unsigned i = 0, e = Elements.size(); i != e; ++i) - Elements[i].reset(); return true; % elif node.is_syntax_collection(): for (auto &E : Elements) { @@ -92,31 +85,29 @@ bool ParsedSyntaxRecorder::formExactLayoutFor(syntax::SyntaxKind Kind, Parsed${node.name} ParsedSyntaxRecorder::record${node.syntax_kind}(${child_params}, ParsedRawSyntaxRecorder &rec) { - ParsedRawSyntaxNode layout[] = { + auto raw = rec.recordRawSyntax(SyntaxKind::${node.syntax_kind}, { % for child in node.children: % if child.is_optional: - ${child.name}.hasValue() ? ${child.name}->takeRaw() : ParsedRawSyntaxNode::null(), + ${child.name}.hasValue() ? ${child.name}->getRaw() : ParsedRawSyntaxNode::null(), % else: - ${child.name}.takeRaw(), + ${child.name}.getRaw(), % end % end - }; - auto raw = rec.recordRawSyntax(SyntaxKind::${node.syntax_kind}, layout); + }); return Parsed${node.name}(std::move(raw)); } Parsed${node.name} ParsedSyntaxRecorder::defer${node.syntax_kind}(${child_params}, SyntaxParsingContext &SPCtx) { - ParsedRawSyntaxNode layout[] = { + auto raw = ParsedRawSyntaxNode::makeDeferred(SyntaxKind::${node.syntax_kind}, { % for child in node.children: % if child.is_optional: - ${child.name}.hasValue() ? ${child.name}->takeRaw() : ParsedRawSyntaxNode::null(), + ${child.name}.hasValue() ? ${child.name}->getRaw() : ParsedRawSyntaxNode::null(), % else: - ${child.name}.takeRaw(), + ${child.name}.getRaw(), % end % end - }; - auto raw = ParsedRawSyntaxNode::makeDeferred(SyntaxKind::${node.syntax_kind}, llvm::makeMutableArrayRef(layout, ${len(node.children)}), SPCtx); + }, SPCtx); return Parsed${node.name}(std::move(raw)); } @@ -131,12 +122,12 @@ ParsedSyntaxRecorder::make${node.syntax_kind}(${child_params}, % elif node.is_syntax_collection(): Parsed${node.name} ParsedSyntaxRecorder::record${node.syntax_kind}( - MutableArrayRef elements, + ArrayRef elements, ParsedRawSyntaxRecorder &rec) { SmallVector layout; layout.reserve(elements.size()); for (auto &element : elements) { - layout.push_back(element.takeRaw()); + layout.push_back(element.getRaw()); } auto raw = rec.recordRawSyntax(SyntaxKind::${node.syntax_kind}, layout); return Parsed${node.name}(std::move(raw)); @@ -144,12 +135,12 @@ ParsedSyntaxRecorder::record${node.syntax_kind}( Parsed${node.name} ParsedSyntaxRecorder::defer${node.syntax_kind}( - MutableArrayRef elements, + ArrayRef elements, SyntaxParsingContext &SPCtx) { SmallVector layout; layout.reserve(elements.size()); for (auto &element : elements) { - layout.push_back(element.takeRaw()); + layout.push_back(element.getRaw()); } auto raw = ParsedRawSyntaxNode::makeDeferred(SyntaxKind::${node.syntax_kind}, layout, SPCtx); @@ -158,7 +149,7 @@ ParsedSyntaxRecorder::defer${node.syntax_kind}( Parsed${node.name} ParsedSyntaxRecorder::make${node.syntax_kind}( - MutableArrayRef elements, + ArrayRef elements, SyntaxParsingContext &SPCtx) { if (SPCtx.shouldDefer()) return defer${node.syntax_kind}(elements, SPCtx); @@ -180,12 +171,12 @@ ParsedSyntaxRecorder::makeBlank${node.syntax_kind}(SourceLoc loc, % elif node.is_unknown(): Parsed${node.name} ParsedSyntaxRecorder::record${node.syntax_kind}( - MutableArrayRef elements, + ArrayRef elements, ParsedRawSyntaxRecorder &rec) { SmallVector layout; layout.reserve(elements.size()); for (auto &element : elements) { - layout.push_back(element.takeRaw()); + layout.push_back(element.getRaw()); } auto raw = rec.recordRawSyntax(SyntaxKind::${node.syntax_kind}, layout); return Parsed${node.name}(std::move(raw)); @@ -193,12 +184,12 @@ ParsedSyntaxRecorder::record${node.syntax_kind}( Parsed${node.name} ParsedSyntaxRecorder::defer${node.syntax_kind}( - MutableArrayRef elements, + ArrayRef elements, SyntaxParsingContext &SPCtx) { SmallVector layout; layout.reserve(elements.size()); for (auto &element : elements) { - layout.push_back(element.takeRaw()); + layout.push_back(element.getRaw()); } auto raw = ParsedRawSyntaxNode::makeDeferred(SyntaxKind::${node.syntax_kind}, layout, SPCtx); return Parsed${node.name}(std::move(raw)); @@ -206,7 +197,7 @@ ParsedSyntaxRecorder::defer${node.syntax_kind}( Parsed${node.name} ParsedSyntaxRecorder::make${node.syntax_kind}( - MutableArrayRef elements, + ArrayRef elements, SyntaxParsingContext &SPCtx) { if (SPCtx.shouldDefer()) return defer${node.syntax_kind}(elements, SPCtx); @@ -233,6 +224,6 @@ ParsedTupleTypeElementSyntax ParsedSyntaxRecorder::makeTupleTypeElement(ParsedTypeSyntax Type, llvm::Optional TrailingComma, SyntaxParsingContext &SPCtx) { - return makeTupleTypeElement(None, None, None, None, std::move(Type), None, None, - std::move(TrailingComma), SPCtx); + return makeTupleTypeElement(None, None, None, None, Type, None, None, + TrailingComma, SPCtx); } diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index f1f4febab0d51..62783da44f29c 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -684,19 +684,19 @@ void Parser::skipSingleSyntax(SmallVectorImpl &Skipped) { Skipped.push_back(consumeTokenSyntax()); skipUntilSyntax(Skipped, tok::r_paren); if (auto RParen = consumeTokenSyntaxIf(tok::r_paren)) - Skipped.push_back(std::move(*RParen)); + Skipped.push_back(*RParen); break; case tok::l_brace: Skipped.push_back(consumeTokenSyntax()); skipUntilSyntax(Skipped, tok::r_brace); if (auto RBrace = consumeTokenSyntaxIf(tok::r_brace)) - Skipped.push_back(std::move(*RBrace)); + Skipped.push_back(*RBrace); break; case tok::l_square: Skipped.push_back(consumeTokenSyntax()); skipUntilSyntax(Skipped, tok::r_square); if (auto RSquare = consumeTokenSyntaxIf(tok::r_square)) - Skipped.push_back(std::move(*RSquare)); + Skipped.push_back(*RSquare); break; case tok::pound_if: case tok::pound_else: @@ -708,7 +708,7 @@ void Parser::skipSingleSyntax(SmallVectorImpl &Skipped) { if (Tok.isAny(tok::pound_else, tok::pound_elseif)) skipSingleSyntax(Skipped); else if (auto Endif = consumeTokenSyntaxIf(tok::pound_endif)) - Skipped.push_back(std::move(*Endif)); + Skipped.push_back(*Endif); break; default: @@ -1003,13 +1003,12 @@ void Parser::skipListUntilDeclRBraceSyntax( while (Tok.isNot(T1, T2, tok::eof, tok::r_brace, tok::pound_endif, tok::pound_else, tok::pound_elseif)) { auto Comma = consumeTokenSyntaxIf(tok::comma); - + if (Comma) + Skipped.push_back(*Comma); + bool hasDelimiter = Tok.getLoc() == startLoc || Comma; bool possibleDeclStartsLine = Tok.isAtStartOfLine(); - if (Comma) - Skipped.push_back(std::move(*Comma)); - if (isStartOfDecl()) { // Could have encountered something like `_ var:` // or `let foo:` or `var:` @@ -1021,7 +1020,7 @@ void Parser::skipListUntilDeclRBraceSyntax( Parser::BacktrackingScope backtrack(*this); // Consume the let or var auto LetOrVar = consumeTokenSyntax(); - Skipped.push_back(std::move(LetOrVar)); + Skipped.push_back(LetOrVar); // If the following token is either or :, it means that // this `var` or `let` should be interpreted as a label @@ -1339,7 +1338,7 @@ Parser::parseListSyntax(tok RightK, SourceLoc LeftLoc, diagnose(Tok, diag::unexpected_separator, ",") .fixItRemove(SourceRange(Tok.getLoc())); auto Comma = consumeTokenSyntax(); - Junk.push_back(std::move(Comma)); + Junk.push_back(Comma); } SourceLoc StartLoc = Tok.getLoc(); diff --git a/lib/Parse/SyntaxParsingContext.cpp b/lib/Parse/SyntaxParsingContext.cpp index e365a87837c51..afe5298d8a095 100644 --- a/lib/Parse/SyntaxParsingContext.cpp +++ b/lib/Parse/SyntaxParsingContext.cpp @@ -54,14 +54,13 @@ size_t SyntaxParsingContext::lookupNode(size_t LexerOffset, SourceLoc Loc) { return 0; } Mode = AccumulationMode::SkippedForIncrementalUpdate; - auto length = foundNode.getRecordedRange().getByteLength(); - getStorage().push_back(std::move(foundNode)); - return length; + getStorage().push_back(foundNode); + return foundNode.getRecordedRange().getByteLength(); } ParsedRawSyntaxNode SyntaxParsingContext::makeUnknownSyntax(SyntaxKind Kind, - MutableArrayRef Parts) { + ArrayRef Parts) { assert(isUnknownKind(Kind)); if (shouldDefer()) return ParsedRawSyntaxNode::makeDeferred(Kind, Parts, *this); @@ -71,12 +70,12 @@ SyntaxParsingContext::makeUnknownSyntax(SyntaxKind Kind, ParsedRawSyntaxNode SyntaxParsingContext::createSyntaxAs(SyntaxKind Kind, - MutableArrayRef Parts, + ArrayRef Parts, SyntaxNodeCreationKind nodeCreateK) { // Try to create the node of the given syntax. ParsedRawSyntaxNode rawNode; auto &rec = getRecorder(); - auto formNode = [&](SyntaxKind kind, MutableArrayRef layout) { + auto formNode = [&](SyntaxKind kind, ArrayRef layout) { if (nodeCreateK == SyntaxNodeCreationKind::Deferred || shouldDefer()) { rawNode = ParsedRawSyntaxNode::makeDeferred(kind, layout, *this); } else { @@ -92,9 +91,9 @@ SyntaxParsingContext::createSyntaxAs(SyntaxKind Kind, Optional SyntaxParsingContext::bridgeAs(SyntaxContextKind Kind, - MutableArrayRef Parts) { + ArrayRef Parts) { if (Parts.size() == 1) { - auto &RawNode = Parts.front(); + auto RawNode = Parts.front(); SyntaxKind RawNodeKind = RawNode.getKind(); switch (Kind) { case SyntaxContextKind::Stmt: @@ -121,7 +120,7 @@ SyntaxParsingContext::bridgeAs(SyntaxContextKind Kind, // We don't need to coerce in this case. break; } - return std::move(RawNode); + return RawNode; } else if (Parts.empty()) { // Just omit the unknown node if it does not have any children return None; @@ -182,7 +181,7 @@ void SyntaxParsingContext::addToken(Token &Tok, /// Add Syntax to the parts. void SyntaxParsingContext::addSyntax(ParsedSyntax Node) { - addRawSyntax(Node.takeRaw()); + addRawSyntax(Node.getRaw()); } void SyntaxParsingContext::createNodeInPlace(SyntaxKind Kind, size_t N, @@ -193,10 +192,12 @@ void SyntaxParsingContext::createNodeInPlace(SyntaxKind Kind, size_t N, return; } - auto node = createSyntaxAs(Kind, getParts().take_back(N), nodeCreateK); - auto &storage = getStorage(); - getStorage().erase(storage.end() - N, getStorage().end()); - getStorage().emplace_back(std::move(node)); + auto I = getStorage().end() - N; + *I = createSyntaxAs(Kind, getParts().take_back(N), nodeCreateK); + + // Remove consumed parts. + if (N != 1) + getStorage().erase(I + 1, getStorage().end()); } void SyntaxParsingContext::createNodeInPlace(SyntaxKind Kind, @@ -249,11 +250,11 @@ void SyntaxParsingContext::collectNodesInPlace(SyntaxKind ColletionKind, ParsedRawSyntaxNode SyntaxParsingContext::finalizeSourceFile() { ParsedRawSyntaxRecorder &Recorder = getRecorder(); - auto Parts = getParts(); - ParsedRawSyntaxNode Layout[2]; + ArrayRef Parts = getParts(); + std::vector AllTopLevel; assert(!Parts.empty() && Parts.back().isToken(tok::eof)); - Layout[1] = std::move(Parts.back()); + ParsedRawSyntaxNode EOFToken = Parts.back(); Parts = Parts.drop_back(); for (auto RawNode : Parts) { @@ -268,13 +269,13 @@ ParsedRawSyntaxNode SyntaxParsingContext::finalizeSourceFile() { AllTopLevel.push_back(RawNode); } - Layout[0] = Recorder.recordRawSyntax(SyntaxKind::CodeBlockItemList, Parts); - + auto itemList = Recorder.recordRawSyntax(SyntaxKind::CodeBlockItemList, + Parts); return Recorder.recordRawSyntax(SyntaxKind::SourceFile, - llvm::makeMutableArrayRef(Layout, 2)); + { itemList, EOFToken }); } -OpaqueSyntaxNode SyntaxParsingContext::finalizeRoot() { + OpaqueSyntaxNode SyntaxParsingContext::finalizeRoot() { assert(isTopOfContextStack() && "some sub-contexts are not destructed"); assert(isRoot() && "only root context can finalize the tree"); assert(Mode == AccumulationMode::Root); @@ -282,7 +283,7 @@ OpaqueSyntaxNode SyntaxParsingContext::finalizeRoot() { return nullptr; // already finalized. } ParsedRawSyntaxNode root = finalizeSourceFile(); - auto opaqueRoot = getSyntaxCreator().finalizeNode(root.takeOpaqueNode()); + auto opaqueRoot = getSyntaxCreator().finalizeNode(root.getOpaqueNode()); // Clear the parts because we will call this function again when destroying // the root context. @@ -302,12 +303,9 @@ void SyntaxParsingContext::synthesize(tok Kind, SourceLoc Loc) { void SyntaxParsingContext::dumpStorage() const { llvm::errs() << "======================\n"; - auto &storage = getStorage(); - for (unsigned i = 0; i != storage.size(); ++i) { - storage[i].dump(llvm::errs()); - llvm::errs() << "\n"; - if (i + 1 == Offset) - llvm::errs() << "--------------\n"; + for (auto Node : getStorage()) { + Node.dump(llvm::errs()); + llvm::errs() << "\n--------------\n"; } } @@ -339,12 +337,14 @@ SyntaxParsingContext::~SyntaxParsingContext() { assert(!isRoot()); if (Storage.size() == Offset) { if (auto BridgedNode = bridgeAs(CtxtKind, {})) { - Storage.push_back(std::move(BridgedNode.getValue())); + Storage.push_back(BridgedNode.getValue()); } } else { - auto node = bridgeAs(CtxtKind, getParts()).getValue(); - Storage.erase(Storage.begin() + Offset, Storage.end()); - Storage.emplace_back(std::move(node)); + auto I = Storage.begin() + Offset; + *I = bridgeAs(CtxtKind, getParts()).getValue(); + // Remove used parts. + if (Storage.size() > Offset + 1) + Storage.erase(Storage.begin() + (Offset + 1), Storage.end()); } break; } @@ -357,12 +357,10 @@ SyntaxParsingContext::~SyntaxParsingContext() { // Remove all parts in this context. case AccumulationMode::Discard: { auto &nodes = getStorage(); - for (auto i = nodes.begin()+Offset, e = nodes.end(); i != e; ++i) { - // FIXME: This should not be needed. This breaks invariant that any - // recorded node must be a part of result souce syntax tree. + for (auto i = nodes.begin()+Offset, e = nodes.end(); i != e; ++i) if (i->isRecorded()) - getRecorder().discardRecordedNode(*i); - } + getSyntaxCreator().finalizeNode(i->getOpaqueNode()); + nodes.erase(nodes.begin()+Offset, nodes.end()); break; } diff --git a/lib/SyntaxParse/RawSyntaxTokenCache.h b/lib/SyntaxParse/RawSyntaxTokenCache.h index e54dcc5223e2b..a200df27ed1a8 100644 --- a/lib/SyntaxParse/RawSyntaxTokenCache.h +++ b/lib/SyntaxParse/RawSyntaxTokenCache.h @@ -39,8 +39,7 @@ class RawSyntaxCacheNode : public llvm::FoldingSetNode { llvm::FoldingSetNodeIDRef IDRef; public: - RawSyntaxCacheNode(RC &Obj, - const llvm::FoldingSetNodeIDRef IDRef) + RawSyntaxCacheNode(RC Obj, const llvm::FoldingSetNodeIDRef IDRef) : Obj(Obj), IDRef(IDRef) {} /// Retrieve assciated RawSyntax. diff --git a/lib/SyntaxParse/SyntaxTreeCreator.cpp b/lib/SyntaxParse/SyntaxTreeCreator.cpp index f5a71dd8ef25b..a20bf39a35a48 100644 --- a/lib/SyntaxParse/SyntaxTreeCreator.cpp +++ b/lib/SyntaxParse/SyntaxTreeCreator.cpp @@ -173,9 +173,3 @@ SyntaxTreeCreator::lookupNode(size_t lexerOffset, syntax::SyntaxKind kind) { raw.resetWithoutRelease(); return {length, opaqueN}; } - -void SyntaxTreeCreator::discardRecordedNode(OpaqueSyntaxNode opaqueN) { - if (!opaqueN) - return; - static_cast(opaqueN)->Release(); -} diff --git a/tools/libSwiftSyntaxParser/libSwiftSyntaxParser.cpp b/tools/libSwiftSyntaxParser/libSwiftSyntaxParser.cpp index cef15dd93715f..898e3506d2f88 100644 --- a/tools/libSwiftSyntaxParser/libSwiftSyntaxParser.cpp +++ b/tools/libSwiftSyntaxParser/libSwiftSyntaxParser.cpp @@ -190,10 +190,6 @@ class CLibParseActions : public SyntaxParseActions { return getNodeHandler()(&node); } - void discardRecordedNode(OpaqueSyntaxNode node) override { - // FIXME: This method should not be called at all. - } - std::pair lookupNode(size_t lexerOffset, SyntaxKind kind) override { auto NodeLookup = getNodeLookup(); From b59cc7ad6a304f2917232df6d37d3e1d1aad4b17 Mon Sep 17 00:00:00 2001 From: Ravi Kandhadai Date: Mon, 16 Sep 2019 14:35:57 -0700 Subject: [PATCH 030/199] [Constant Evaluator] Add support to the constant evaluator for: 1. builtin "int_expect", which makes the evaluator work on more integer operations such as left/right shift (with traps) and integer conversions. 2. builtin "_assertConfiguration", which enables the evaluator to work with debug stdlib. 3. builtin "ptrtoint", which enables the evaluator to track StaticString 4. _assertionFailure API, which enables the evaluator to report stdlib assertion failures encountered during constant evaluation. Also, enable attaching auxiliary data with the enum "UnknownReason" and use it to improve diagnostics for UnknownSymbolicValues, which represent failures during constant evaluation. --- include/swift/AST/Builtins.def | 2 + include/swift/AST/DiagnosticsSIL.def | 52 ++-- include/swift/SIL/SILConstants.h | 145 ++++++--- include/swift/SILOptimizer/Utils/ConstExpr.h | 6 +- lib/AST/Builtins.cpp | 2 +- lib/SIL/OperandOwnership.cpp | 1 + lib/SIL/SILConstants.cpp | 136 ++++++--- lib/SIL/ValueOwnership.cpp | 1 + lib/SILOptimizer/Utils/ConstExpr.cpp | 275 +++++++++++------- test/SILOptimizer/constant_evaluator_test.sil | 63 +++- test/SILOptimizer/pound_assert.swift | 3 - 11 files changed, 473 insertions(+), 213 deletions(-) diff --git a/include/swift/AST/Builtins.def b/include/swift/AST/Builtins.def index 485f6be9db6ce..49472b61137d3 100644 --- a/include/swift/AST/Builtins.def +++ b/include/swift/AST/Builtins.def @@ -75,6 +75,8 @@ BUILTIN_BINARY_OPERATION(ExactUDiv, "udiv_exact", "n", IntegerOrVector) BUILTIN_BINARY_OPERATION(URem, "urem", "n", Integer) BUILTIN_BINARY_OPERATION(FRem, "frem", "n", FloatOrVector) BUILTIN_BINARY_OPERATION(Xor, "xor", "n", IntegerOrVector) +// This builtin is an optimizer hint and always returns the first argument. +BUILTIN_BINARY_OPERATION(Expect, "int_expect", "n", Integer) #undef BUILTIN_BINARY_OPERATION /// These builtins are analogous the similarly named llvm intrinsics. The diff --git a/include/swift/AST/DiagnosticsSIL.def b/include/swift/AST/DiagnosticsSIL.def index df73e868a0c2c..66f04071c3d35 100644 --- a/include/swift/AST/DiagnosticsSIL.def +++ b/include/swift/AST/DiagnosticsSIL.def @@ -360,27 +360,37 @@ ERROR(pound_assert_failure,none, NOTE(constexpr_unknown_reason_default,none, "cannot evaluate expression as constant here", ()) NOTE(constexpr_unevaluable_operation,none, - "cannot constant evaluate operation", ()) + "cannot constant evaluate operation%select{| used by this call}0", (bool)) NOTE(constexpr_too_many_instructions,none, "exceeded instruction limit: %0 when evaluating the expression " "at compile time", (unsigned)) -NOTE(constexpr_limit_exceeding_instruction,none, "limit exceeded here", ()) +NOTE(constexpr_limit_exceeding_instruction,none, "limit exceeded " + "%select{here|during this call}0", (bool)) NOTE(constexpr_loop_found_note,none, "control-flow loop found during evaluation ", ()) -NOTE(constexpr_loop_instruction,none, "found loop here", ()) +NOTE(constexpr_loop_instruction,none, "found loop " + "%select{here|inside this call}0", (bool)) NOTE(constexpr_overflow,none, "integer overflow detected", ()) -NOTE(constexpr_overflow_operation,none, "operation overflows", ()) +NOTE(constexpr_overflow_operation,none, "operation" + "%select{| performed during this call}0 overflows", (bool)) NOTE(constexpr_trap,none, "trap detected", ()) -NOTE(constexpr_trap_operation,none, "operation traps", ()) +NOTE(constexpr_trap_operation,none, "operation" + "%select{| performed during this call}0 traps", (bool)) + +NOTE(constexpr_assertion_failed, none, "assertion failed with message: %0", + (StringRef)) +NOTE(constexpr_assertion_failed_here, none, "assertion failed" + "%select{ here| during this call}0 ", (bool)) NOTE(constexpr_invalid_operand_seen, none, "operation with invalid operands encountered during evaluation",()) NOTE(constexpr_operand_invalid_here, none, - "operation with invalid operands encountered here",()) + "operation with invalid operands encountered " + "%select{here|during this call}0", (bool)) NOTE(constexpr_value_unknown_at_top_level,none, "cannot evaluate top-level value as constant here",()) @@ -388,26 +398,29 @@ NOTE(constexpr_multiple_writers_found_at_top_level,none, "top-level value has multiple assignments",()) NOTE(constexpr_unsupported_instruction_found, none, - "encountered operation not supported by the evaluator", ()) -NOTE(constexpr_unsupported_instruction_found_here,none, - "operation not supported by the evaluator", ()) + "encountered operation not supported by the evaluator: %0", (StringRef)) +NOTE(constexpr_unsupported_instruction_found_here,none, "operation" + "%select{| used by this call is}0 not supported by the evaluator", (bool)) NOTE(constexpr_unknown_function_called, none, - "encountered call to a function whose body is not available", ()) + "encountered call to '%0' whose body is not available", (StringRef)) NOTE(constexpr_unknown_function_called_here, none, - "call to a function whose body is not available", ()) + "%select{|calls a }0function whose body is not available", (bool)) NOTE(constexpr_untracked_sil_value_use_found, none, "encountered use of a variable not tracked by the evaluator", ()) NOTE(constexpr_untracked_sil_value_used_here, none, - "untracked variable used here", ()) - -NOTE(constexpr_witness_call_with_no_conformance_found, none, - "cannot find concrete conformance for a witness method call", ()) -NOTE(constexpr_witness_call_with_no_target_found, none, - "cannot resolve a witness method call to a concrete function", ()) -NOTE(constexpr_witness_call_found_here, none, - "witness method call found here", ()) + "untracked variable used %select{here|by this call}0", (bool)) + +NOTE(constexpr_unresolvable_witness_call, none, + "encountered unresolvable witness method call: '%0'", (StringRef)) +NOTE(constexpr_no_witness_table_entry, none, "cannot find witness table entry " + "%select{for this call|for a witness-method invoked during this call}0", + (bool)) +NOTE(constexpr_witness_call_with_no_conformance, none, + "cannot find concrete conformance " + "%select{for this call|for a witness-method invoked during this call}0", + (bool)) NOTE(constexpr_unknown_control_flow_due_to_skip,none, "branch depends on " "non-constant value produced by an unevaluated instructions", ()) @@ -415,6 +428,7 @@ NOTE(constexpr_returned_by_unevaluated_instruction,none, "return value of an unevaluated instruction is not a constant", ()) NOTE(constexpr_mutated_by_unevaluated_instruction,none, "value mutable by an " "unevaluated instruction is not a constant", ()) +ERROR(not_constant_evaluable, none, "not constant evaluable", ()) ERROR(non_physical_addressof,none, "addressof only works with purely physical lvalues; " diff --git a/include/swift/SIL/SILConstants.h b/include/swift/SIL/SILConstants.h index 71a0a0e1ba8e8..1a6bd25012436 100644 --- a/include/swift/SIL/SILConstants.h +++ b/include/swift/SIL/SILConstants.h @@ -41,63 +41,119 @@ extern llvm::cl::opt ConstExprLimit; /// allowing the caller to produce a specific diagnostic. The "Unknown" /// SymbolicValue representation also includes a pointer to the SILNode in /// question that was problematic. -enum class UnknownReason { - // TODO: Eliminate the default code, by making classifications for each - // failure mode. - Default, +class UnknownReason { +public: + enum UnknownKind { + // TODO: Eliminate the default kind, by making classifications for each + // failure mode. + Default, + + /// The constant expression was too big. This is reported on a random + /// instruction within the constexpr that triggered the issue. + TooManyInstructions, + + /// A control flow loop was found. + Loop, + + /// Integer overflow detected. + Overflow, + + /// Unspecified trap detected. + Trap, + + /// Assertion failure detected. These have an associated message unlike + /// traps. + AssertionFailure, - /// The constant expression was too big. This is reported on a random - /// instruction within the constexpr that triggered the issue. - TooManyInstructions, + /// An operation was applied over operands whose symbolic values were + /// constants but were not valid for the operation. + InvalidOperandValue, - /// A control flow loop was found. - Loop, + /// Encountered an instruction not supported by the interpreter. + UnsupportedInstruction, - /// Integer overflow detected. - Overflow, + /// Encountered a function call where the body of the called function is + /// not available. + CalleeImplementationUnknown, - /// Unspecified trap detected. - Trap, + /// Attempted to load from/store into a SIL value that was not tracked by + /// the interpreter. + UntrackedSILValue, - /// An operation was applied over operands whose symbolic values were - /// constants but were not valid for the operation. - InvalidOperandValue, + /// Attempted to find a concrete protocol conformance for a witness method + /// and failed. + UnknownWitnessMethodConformance, - /// Encountered an instruction not supported by the interpreter. - UnsupportedInstruction, + /// Attempted to determine the SIL function of a witness method and failed. + NoWitnesTableEntry, - /// Encountered a function call where the body of the called function is - /// not available. - CalleeImplementationUnknown, + /// The value of a top-level variable cannot be determined to be a constant. + /// This is only relevant in the backward evaluation mode, which is used by + /// #assert. + NotTopLevelConstant, - /// Attempted to load from/store into a SIL value that was not tracked by - /// the interpreter. - UntrackedSILValue, + /// A top-level value has multiple writers. This is only relevant in the + /// non-flow-sensitive evaluation mode, which is used by #assert. + MutipleTopLevelWriters, - /// Attempted to find a concrete protocol conformance for a witness method - /// and failed. - UnknownWitnessMethodConformance, + /// Indicates the return value of an instruction that was not evaluated + /// during interpretation. + ReturnedByUnevaluatedInstruction, - /// Attempted to determine the SIL function of a witness method (based on a - /// concrete protocol conformance) and failed. - UnresolvableWitnessMethod, + /// Indicates that the value was possibly modified by an instruction + /// that was not evaluated during the interpretation. + MutatedByUnevaluatedInstruction, + }; - /// The value of a top-level variable cannot be determined to be a constant. - /// This is only relevant in the backward evaluation mode, which is used by - /// #assert. - NotTopLevelConstant, +private: + UnknownKind kind; - /// A top-level value has multiple writers. This is only relevant in the - /// non-flow-sensitive evaluation mode, which is used by #assert. - MutipleTopLevelWriters, + // Auxiliary information for different unknown kinds. + union { + SILFunction *function; + const char *failedAssertMessage; + } payload; - /// Indicates the return value of an instruction that was not evaluated during - /// interpretation. - ReturnedByUnevaluatedInstruction, +public: + UnknownKind getKind() { return kind; } - /// Indicates that the value was possibly modified by an instruction - /// that was not evaluated during the interpretation. - MutatedByUnevaluatedInstruction, + static bool isUnknownKindWithPayload(UnknownKind kind) { + return kind == UnknownKind::CalleeImplementationUnknown; + } + + static UnknownReason create(UnknownKind kind) { + assert(!isUnknownKindWithPayload(kind)); + UnknownReason reason; + reason.kind = kind; + return reason; + } + + static UnknownReason createCalleeImplementationUnknown(SILFunction *callee) { + assert(callee); + UnknownReason reason; + reason.kind = UnknownKind::CalleeImplementationUnknown; + reason.payload.function = callee; + return reason; + } + + SILFunction *getCalleeWithoutImplmentation() { + assert(kind == UnknownKind::CalleeImplementationUnknown); + return payload.function; + } + + static UnknownReason createAssertionFailure(const char *message, + size_t size) { + assert(message[size] == '\0' && "message must be null-terminated"); + UnknownReason reason; + reason.kind = UnknownKind::AssertionFailure; + reason.payload.failedAssertMessage = message; + return reason; + } + + const char *getAssertionFailureMessage() { + assert(kind == UnknownKind::AssertionFailure); + return payload.failedAssertMessage; + } }; /// An abstract class that exposes functions for allocating symbolic values. @@ -241,9 +297,6 @@ class SymbolicValue { RepresentationKind representationKind : 8; union { - /// This is the reason code for RK_Unknown values. - UnknownReason unknownReason : 32; - /// This is the number of bits in an RK_Integer or RK_IntegerInline /// representation, which makes the number of entries in the list derivable. unsigned integerBitwidth; diff --git a/include/swift/SILOptimizer/Utils/ConstExpr.h b/include/swift/SILOptimizer/Utils/ConstExpr.h index 7cd8b452d4e2e..cfe04cdb164a6 100644 --- a/include/swift/SILOptimizer/Utils/ConstExpr.h +++ b/include/swift/SILOptimizer/Utils/ConstExpr.h @@ -38,7 +38,7 @@ class SILNode; class SymbolicValue; class SymbolicValueAllocator; class ConstExprFunctionState; -enum class UnknownReason; +class UnknownReason; /// This class is the main entrypoint for evaluating constant expressions. It /// also handles caching of previously computed constexpr results. @@ -162,8 +162,6 @@ class ConstExprStepEvaluator { Optional lookupConstValue(SILValue value); - bool isKnownFunction(SILFunction *fun); - /// Returns true if and only if `errorVal` denotes an error that requires /// aborting interpretation and returning the error. Skipping an instruction /// that produces such errors is not a valid behavior. @@ -177,5 +175,7 @@ class ConstExprStepEvaluator { unsigned instructionsEvaluatedByLastEvaluation() { return stepsEvaluated; } }; +bool isKnownConstantEvaluableFunction(SILFunction *fun); + } // end namespace swift #endif diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index beb25d4bf6c1b..efa3bec1a2dd4 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -1779,7 +1779,7 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { #define BUILTIN_BINARY_OPERATION(id, name, attrs, overload) case BuiltinValueKind::id: #include "swift/AST/Builtins.def" if (Types.size() != 1) return nullptr; - return getBinaryOperation(Id, Types[0]); + return getBinaryOperation(Id, Types[0]); #define BUILTIN(id, name, Attrs) #define BUILTIN_BINARY_OPERATION_WITH_OVERFLOW(id, name, _, attrs, overload) case BuiltinValueKind::id: diff --git a/lib/SIL/OperandOwnership.cpp b/lib/SIL/OperandOwnership.cpp index b8294215adcca..62f729b7b8459 100644 --- a/lib/SIL/OperandOwnership.cpp +++ b/lib/SIL/OperandOwnership.cpp @@ -1003,6 +1003,7 @@ ANY_OWNERSHIP_BUILTIN(SRem) ANY_OWNERSHIP_BUILTIN(SSubOver) ANY_OWNERSHIP_BUILTIN(SToSCheckedTrunc) ANY_OWNERSHIP_BUILTIN(SToUCheckedTrunc) +ANY_OWNERSHIP_BUILTIN(Expect) ANY_OWNERSHIP_BUILTIN(Shl) ANY_OWNERSHIP_BUILTIN(Sizeof) ANY_OWNERSHIP_BUILTIN(StaticReport) diff --git a/lib/SIL/SILConstants.cpp b/lib/SIL/SILConstants.cpp index 59045989bdcbc..711bee1a375c0 100644 --- a/lib/SIL/SILConstants.cpp +++ b/lib/SIL/SILConstants.cpp @@ -42,7 +42,7 @@ void SymbolicValue::print(llvm::raw_ostream &os, unsigned indent) const { os << "uninit\n"; return; case RK_Unknown: { - os << "unknown(" << (int)getUnknownReason() << "): "; + os << "unknown(" << (int)getUnknownReason().getKind() << "): "; getUnknownNode()->dump(); return; } @@ -571,9 +571,18 @@ SymbolicValue SymbolicValue::lookThroughSingleElementAggregates() const { } bool SymbolicValue::isUnknownDueToUnevaluatedInstructions() { - auto unknownReason = getUnknownReason(); - return (unknownReason == UnknownReason::ReturnedByUnevaluatedInstruction || - unknownReason == UnknownReason::MutatedByUnevaluatedInstruction); + auto unknownKind = getUnknownReason().getKind(); + return (unknownKind == UnknownReason::ReturnedByUnevaluatedInstruction || + unknownKind == UnknownReason::MutatedByUnevaluatedInstruction); +} + +static void getWitnessMethodName(WitnessMethodInst *witnessMethodInst, + SmallVectorImpl &methodName) { + assert(witnessMethodInst); + SILDeclRef witnessMember = witnessMethodInst->getMember(); + if (witnessMember.hasDecl()) { + witnessMember.getDecl()->getFullName().getString(methodName); + } } /// Given that this is an 'Unknown' value, emit diagnostic notes providing @@ -587,12 +596,20 @@ void SymbolicValue::emitUnknownDiagnosticNotes(SILLocation fallbackLoc) { ASTContext &ctx = unknownNode->getModule()->getASTContext(); // Extract the location of the instruction/construct that triggered the error - // during interpretation, if available. - Optional triggerLoc = None; - if (auto badInst = dyn_cast(unknownNode)) { - triggerLoc = skipInternalLocations(badInst->getDebugLocation()) - .getLocation() - .getSourceLoc(); + // during interpretation, if available. If the instruction is internal to + // stdlib and has an invalid location, find the innermost call that has a + // valid location. + SourceLoc triggerLoc; + bool triggerLocSkipsInternalLocs = false; + if (auto *badInst = dyn_cast(unknownNode)) { + SILDebugLocation debugLoc = badInst->getDebugLocation(); + SourceLoc initialSourceLoc = debugLoc.getLocation().getSourceLoc(); + if (initialSourceLoc.isValid()) { + triggerLoc = initialSourceLoc; + } else { + triggerLocSkipsInternalLocs = true; + triggerLoc = skipInternalLocations(debugLoc).getLocation().getSourceLoc(); + } } // Determine the top-level expression where the error happens and use it as @@ -602,7 +619,7 @@ void SymbolicValue::emitUnknownDiagnosticNotes(SILLocation fallbackLoc) { // the faulty top-level expression location cannot be found. auto diagLoc = errorCallStack.empty() - ? (triggerLoc ? triggerLoc.getValue() : fallbackLoc.getSourceLoc()) + ? (triggerLoc.isValid() ? triggerLoc : fallbackLoc.getSourceLoc()) : errorCallStack.front(); if (diagLoc.isInvalid()) { return; @@ -611,79 +628,126 @@ void SymbolicValue::emitUnknownDiagnosticNotes(SILLocation fallbackLoc) { // Emit a note at the trigger location as well if it is different from the // top-level expression. bool emitTriggerLocInDiag = - triggerLoc ? diagLoc != triggerLoc.getValue() : false; + triggerLoc.isValid() ? diagLoc != triggerLoc : false; - switch (unknownReason) { + switch (unknownReason.getKind()) { case UnknownReason::Default: diagnose(ctx, diagLoc, diag::constexpr_unknown_reason_default); if (emitTriggerLocInDiag) - diagnose(ctx, *triggerLoc, diag::constexpr_unevaluable_operation); + diagnose(ctx, triggerLoc, diag::constexpr_unevaluable_operation, + triggerLocSkipsInternalLocs); return; case UnknownReason::TooManyInstructions: diagnose(ctx, diagLoc, diag::constexpr_too_many_instructions, ConstExprLimit); if (emitTriggerLocInDiag) - diagnose(ctx, *triggerLoc, diag::constexpr_limit_exceeding_instruction); + diagnose(ctx, triggerLoc, diag::constexpr_limit_exceeding_instruction, + triggerLocSkipsInternalLocs); return; case UnknownReason::Loop: diagnose(ctx, diagLoc, diag::constexpr_loop_found_note); if (emitTriggerLocInDiag) - diagnose(ctx, *triggerLoc, diag::constexpr_loop_instruction); + diagnose(ctx, triggerLoc, diag::constexpr_loop_instruction, + triggerLocSkipsInternalLocs); return; case UnknownReason::Overflow: diagnose(ctx, diagLoc, diag::constexpr_overflow); if (emitTriggerLocInDiag) - diagnose(ctx, *triggerLoc, diag::constexpr_overflow_operation); + diagnose(ctx, triggerLoc, diag::constexpr_overflow_operation, + triggerLocSkipsInternalLocs); return; case UnknownReason::Trap: diagnose(ctx, diagLoc, diag::constexpr_trap); if (emitTriggerLocInDiag) - diagnose(ctx, *triggerLoc, diag::constexpr_trap_operation); + diagnose(ctx, triggerLoc, diag::constexpr_trap_operation, + triggerLocSkipsInternalLocs); + return; + case UnknownReason::AssertionFailure: { + const char *message = unknownReason.getAssertionFailureMessage(); + diagnose(ctx, diagLoc, diag::constexpr_assertion_failed, + StringRef(message)); + if (emitTriggerLocInDiag) + diagnose(ctx, triggerLoc, diag::constexpr_assertion_failed_here, + triggerLocSkipsInternalLocs); return; + } case UnknownReason::InvalidOperandValue: diagnose(ctx, diagLoc, diag::constexpr_invalid_operand_seen); if (emitTriggerLocInDiag) - diagnose(ctx, *triggerLoc, diag::constexpr_operand_invalid_here); + diagnose(ctx, triggerLoc, diag::constexpr_operand_invalid_here, + triggerLocSkipsInternalLocs); return; case UnknownReason::NotTopLevelConstant: { // For top-level errors, trigger loc is better than diagLoc. - auto loc = emitTriggerLocInDiag ? *triggerLoc : diagLoc; + auto loc = emitTriggerLocInDiag ? triggerLoc : diagLoc; diagnose(ctx, loc, diag::constexpr_value_unknown_at_top_level); return; } case UnknownReason::MutipleTopLevelWriters: { // For top-level errors, trigger loc is better than diagLoc. - auto loc = emitTriggerLocInDiag ? *triggerLoc : diagLoc; + auto loc = emitTriggerLocInDiag ? triggerLoc : diagLoc; diagnose(ctx, loc, diag::constexpr_multiple_writers_found_at_top_level); return; } - case UnknownReason::UnsupportedInstruction: - diagnose(ctx, diagLoc, diag::constexpr_unsupported_instruction_found); + case UnknownReason::UnsupportedInstruction: { + // Get the name of the unsupported instruction. + auto *unsupportedInst = dyn_cast(unknownNode); + assert(unsupportedInst); + SmallString<4> instName(getSILInstructionName(unsupportedInst->getKind())); + if (auto *builtinInst = dyn_cast(unsupportedInst)) { + instName.append(" "); + instName.append(builtinInst->getName().str()); + } + + diagnose(ctx, diagLoc, diag::constexpr_unsupported_instruction_found, + instName); if (emitTriggerLocInDiag) - diagnose(ctx, *triggerLoc, - diag::constexpr_unsupported_instruction_found_here); + diagnose(ctx, triggerLoc, + diag::constexpr_unsupported_instruction_found_here, + triggerLocSkipsInternalLocs); return; - case UnknownReason::CalleeImplementationUnknown: - diagnose(ctx, diagLoc, diag::constexpr_unknown_function_called); + } + case UnknownReason::CalleeImplementationUnknown: { + SILFunction *callee = unknownReason.getCalleeWithoutImplmentation(); + std::string demangledCalleeName = + Demangle::demangleSymbolAsString(callee->getName()); + diagnose(ctx, diagLoc, diag::constexpr_unknown_function_called, + StringRef(demangledCalleeName)); if (emitTriggerLocInDiag) - diagnose(ctx, *triggerLoc, diag::constexpr_unknown_function_called_here); + diagnose(ctx, triggerLoc, diag::constexpr_unknown_function_called_here, + triggerLocSkipsInternalLocs); return; + } case UnknownReason::UntrackedSILValue: diagnose(ctx, diagLoc, diag::constexpr_untracked_sil_value_use_found); if (emitTriggerLocInDiag) - diagnose(ctx, *triggerLoc, diag::constexpr_untracked_sil_value_used_here); + diagnose(ctx, triggerLoc, diag::constexpr_untracked_sil_value_used_here, + triggerLocSkipsInternalLocs); return; - case UnknownReason::UnknownWitnessMethodConformance: - diagnose(ctx, diagLoc, - diag::constexpr_witness_call_with_no_conformance_found); + case UnknownReason::UnknownWitnessMethodConformance: { + SmallString<8> witnessMethodName; + getWitnessMethodName(dyn_cast(unknownNode), + witnessMethodName); + diagnose(ctx, diagLoc, diag::constexpr_unresolvable_witness_call, + witnessMethodName); if (emitTriggerLocInDiag) - diagnose(ctx, *triggerLoc, diag::constexpr_witness_call_found_here); + diagnose(ctx, triggerLoc, + diag::constexpr_witness_call_with_no_conformance, + triggerLocSkipsInternalLocs); return; - case UnknownReason::UnresolvableWitnessMethod: - diagnose(ctx, diagLoc, diag::constexpr_witness_call_with_no_target_found); + } + case UnknownReason::NoWitnesTableEntry: { + SmallString<8> witnessMethodName; + getWitnessMethodName(dyn_cast(unknownNode), + witnessMethodName); + + diagnose(ctx, diagLoc, diag::constexpr_unresolvable_witness_call, + StringRef(witnessMethodName)); if (emitTriggerLocInDiag) - diagnose(ctx, *triggerLoc, diag::constexpr_witness_call_found_here); + diagnose(ctx, triggerLoc, diag::constexpr_no_witness_table_entry, + triggerLocSkipsInternalLocs); return; + } case UnknownReason::ReturnedByUnevaluatedInstruction: diagnose(ctx, diagLoc, diag::constexpr_returned_by_unevaluated_instruction); break; diff --git a/lib/SIL/ValueOwnership.cpp b/lib/SIL/ValueOwnership.cpp index 7249147e513bd..5b8530fb09c60 100644 --- a/lib/SIL/ValueOwnership.cpp +++ b/lib/SIL/ValueOwnership.cpp @@ -427,6 +427,7 @@ CONSTANT_OWNERSHIP_BUILTIN(Any, SIToFP) CONSTANT_OWNERSHIP_BUILTIN(Any, SMulOver) CONSTANT_OWNERSHIP_BUILTIN(Any, SRem) CONSTANT_OWNERSHIP_BUILTIN(Any, SSubOver) +CONSTANT_OWNERSHIP_BUILTIN(Any, Expect) CONSTANT_OWNERSHIP_BUILTIN(Any, Shl) CONSTANT_OWNERSHIP_BUILTIN(Any, Sub) CONSTANT_OWNERSHIP_BUILTIN(Any, Trunc) diff --git a/lib/SILOptimizer/Utils/ConstExpr.cpp b/lib/SILOptimizer/Utils/ConstExpr.cpp index 0c5846835fda5..329179569c719 100644 --- a/lib/SILOptimizer/Utils/ConstExpr.cpp +++ b/lib/SILOptimizer/Utils/ConstExpr.cpp @@ -30,8 +30,7 @@ using namespace swift; static llvm::Optional evaluateAndCacheCall(SILFunction &fn, SubstitutionMap substitutionMap, - ArrayRef arguments, - SmallVectorImpl &results, + ArrayRef arguments, SymbolicValue &result, unsigned &numInstEvaluated, ConstExprEvaluator &evaluator); // TODO: ConstantTracker in the performance inliner and the @@ -48,7 +47,9 @@ enum class WellKnownFunction { // static String.== infix(_: String) StringEquals, // String.percentEscapedString.getter - StringEscapePercent + StringEscapePercent, + // _assertionFailure(_: StaticString, _: StaticString, file: StaticString,...) + AssertionFailure }; static llvm::Optional classifyFunction(SILFunction *fn) { @@ -65,9 +66,17 @@ static llvm::Optional classifyFunction(SILFunction *fn) { return WellKnownFunction::StringEquals; if (fn->hasSemanticsAttr("string.escapePercent.get")) return WellKnownFunction::StringEscapePercent; + if (fn->hasSemanticsAttrThatStartsWith("programtermination_point")) + return WellKnownFunction::AssertionFailure; return None; } +/// Helper function for creating UnknownReason without a payload. +static SymbolicValue getUnknown(ConstExprEvaluator &evaluator, SILNode *node, + UnknownReason::UnknownKind kind) { + return evaluator.getUnknown(node, UnknownReason::create(kind)); +} + //===----------------------------------------------------------------------===// // ConstExprFunctionState implementation. //===----------------------------------------------------------------------===// @@ -109,6 +118,19 @@ class ConstExprFunctionState { : evaluator(evaluator), fn(fn), substitutionMap(substitutionMap), numInstEvaluated(numInstEvaluated) {} + /// Pretty print the state to stderr. + void dump() const { + llvm::errs() << "[ConstExprState: \n"; + llvm::errs() << " Caller: " << (fn ? fn->getName() : "null") << "\n"; + llvm::errs() << " evaluatedInstrCount: " << numInstEvaluated << "\n"; + llvm::errs() << " SubstMap: \n"; + substitutionMap.dump(llvm::errs(), SubstitutionMap::DumpStyle::Full, 6); + llvm::errs() << "\n calculatedValues: "; + for (auto kv : calculatedValues) { + llvm::errs() << " " << kv.first << " --> " << kv.second << "\n"; + } + } + void setValue(SILValue value, SymbolicValue symVal) { calculatedValues.insert({value, symVal}); } @@ -330,12 +352,10 @@ SymbolicValue ConstExprFunctionState::computeConstantValue(SILValue value) { auto confResult = substitutionMap.lookupConformance( wmi->getLookupType(), wmi->getConformance().getRequirement()); if (!confResult) - return evaluator.getUnknown( - value, UnknownReason::UnknownWitnessMethodConformance); + return getUnknown(evaluator, value, + UnknownReason::UnknownWitnessMethodConformance); auto conf = confResult.getValue(); auto &module = wmi->getModule(); - - // Look up the conformance's witness table and the member out of it. SILFunction *fn = module.lookUpFunctionInWitnessTable(conf, wmi->getMember()).first; // If we were able to resolve it, then we can proceed. @@ -344,8 +364,7 @@ SymbolicValue ConstExprFunctionState::computeConstantValue(SILValue value) { LLVM_DEBUG(llvm::dbgs() << "ConstExpr Unresolved witness: " << *value << "\n"); - return evaluator.getUnknown(value, - UnknownReason::UnresolvableWitnessMethod); + return getUnknown(evaluator, value, UnknownReason::NoWitnesTableEntry); } if (auto *builtin = dyn_cast(value)) @@ -417,17 +436,30 @@ SymbolicValue ConstExprFunctionState::computeConstantValue(SILValue value) { auto unknownReason = isa(value) ? UnknownReason::UnsupportedInstruction : UnknownReason::Default; - return evaluator.getUnknown(value, unknownReason); + return getUnknown(evaluator, value, unknownReason); } SymbolicValue ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) { const BuiltinInfo &builtin = inst->getBuiltinInfo(); + // Constant builtins. + if (inst->getNumOperands() == 0) { + switch (builtin.ID) { + default: + break; + case BuiltinValueKind::AssertConf: + // Pretend that asserts are enabled during evaluation so that assertion + // failures during interpretation are caught and reported. + // Int32(0) - represents a debug assert configuration. + return SymbolicValue::getInteger(0, 32); + } + } + // Handle various cases in groups. - auto unknownResult = [&]() -> SymbolicValue { - return evaluator.getUnknown(SILValue(inst), - UnknownReason::InvalidOperandValue); + auto invalidOperandValue = [&]() -> SymbolicValue { + return getUnknown(evaluator, SILValue(inst), + UnknownReason::InvalidOperandValue); }; // Unary operations. @@ -446,7 +478,7 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) { auto IntCheckedTruncFn = [&](bool srcSigned, bool dstSigned) -> SymbolicValue { if (operand.getKind() != SymbolicValue::Integer) - return unknownResult(); + return invalidOperandValue(); APInt operandVal = operand.getIntegerValue(); uint32_t srcBitWidth = operandVal.getBitWidth(); @@ -469,7 +501,7 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) { overflowed |= result.isSignBitSet(); if (overflowed) - return evaluator.getUnknown(SILValue(inst), UnknownReason::Overflow); + return getUnknown(evaluator, SILValue(inst), UnknownReason::Overflow); } auto &allocator = evaluator.getAllocator(); @@ -499,7 +531,7 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) { case BuiltinValueKind::SExt: case BuiltinValueKind::SExtOrBitCast: { if (operand.getKind() != SymbolicValue::Integer) - return unknownResult(); + return invalidOperandValue(); unsigned destBitWidth = inst->getType().castTo()->getGreatestWidth(); @@ -525,6 +557,17 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) { } return SymbolicValue::getInteger(result, evaluator.getAllocator()); } + case BuiltinValueKind::PtrToInt: { + // This is operation is supported only for string constants. This is + // because this builtin is used by the initializer of StaticString which + // is used in preconditions and assertion failures. Supporting this + // enables the evaluator to handle assertion/precondition failures. + if (operand.getKind() != SymbolicValue::String) { + return getUnknown(evaluator, SILValue(inst), + UnknownReason::UnsupportedInstruction); + } + return operand; + } } } @@ -542,7 +585,7 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) { -> SymbolicValue { if (operand0.getKind() != SymbolicValue::Integer || operand1.getKind() != SymbolicValue::Integer) - return unknownResult(); + return invalidOperandValue(); auto result = fn(operand0.getIntegerValue(), operand1.getIntegerValue()); return SymbolicValue::getInteger(APInt(1, result), @@ -552,7 +595,7 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) { #define REQUIRE_KIND(KIND) \ if (operand0.getKind() != SymbolicValue::KIND || \ operand1.getKind() != SymbolicValue::KIND) \ - return unknownResult(); + return invalidOperandValue(); switch (builtin.ID) { default: @@ -595,6 +638,9 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) { INT_COMPARE(ICMP_UGE, l.uge(r)); #undef INT_COMPARE #undef REQUIRE_KIND + + case BuiltinValueKind::Expect: + return operand0; } } @@ -618,7 +664,7 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) { if (operand0.getKind() != SymbolicValue::Integer || operand1.getKind() != SymbolicValue::Integer || operand2.getKind() != SymbolicValue::Integer) - return unknownResult(); + return invalidOperandValue(); auto l = operand0.getIntegerValue(), r = operand1.getIntegerValue(); bool overflowed = false; @@ -627,7 +673,7 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) { // Return a statically diagnosed overflow if the operation is supposed to // trap on overflow. if (overflowed && !operand2.getIntegerValue().isNullValue()) - return evaluator.getUnknown(SILValue(inst), UnknownReason::Overflow); + return getUnknown(evaluator, SILValue(inst), UnknownReason::Overflow); auto &allocator = evaluator.getAllocator(); // Build the Symbolic value result for our normal and overflow bit. @@ -660,8 +706,8 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) { LLVM_DEBUG(llvm::dbgs() << "ConstExpr Unknown Builtin: " << *inst << "\n"); // Otherwise, we don't know how to handle this builtin. - return evaluator.getUnknown(SILValue(inst), - UnknownReason::UnsupportedInstruction); + return getUnknown(evaluator, SILValue(inst), + UnknownReason::UnsupportedInstruction); } // Handle calls to opaque callees, either by handling them and returning None or @@ -670,8 +716,9 @@ llvm::Optional ConstExprFunctionState::computeOpaqueCallResult(ApplyInst *apply, SILFunction *callee) { LLVM_DEBUG(llvm::dbgs() << "ConstExpr Opaque Callee: " << *callee << "\n"); - return evaluator.getUnknown((SILInstruction *)apply, - UnknownReason::CalleeImplementationUnknown); + return evaluator.getUnknown( + (SILInstruction *)apply, + UnknownReason::createCalleeImplementationUnknown(callee)); } /// Given a call to a well known function, collect its arguments as constants, @@ -683,6 +730,34 @@ ConstExprFunctionState::computeWellKnownCallResult(ApplyInst *apply, WellKnownFunction callee) { auto conventions = apply->getSubstCalleeConv(); switch (callee) { + case WellKnownFunction::AssertionFailure: { + // Extract the strings from the StaticString arguments and create a + // null-terminated assertion failure message. + SmallString<4> message; + for (SILValue argument : apply->getArguments()) { + SymbolicValue argValue = getConstantValue(argument); + if (argValue.getKind() != SymbolicValue::Aggregate) + continue; + + ArrayRef staticStringProps = argValue.getAggregateValue(); + if (staticStringProps.empty() || + staticStringProps[0].getKind() != SymbolicValue::String) + continue; + + message += staticStringProps[0].getStringValue(); + message += ": "; + } + if (message.empty()) + message += ""; + + size_t size = message.size(); + char *messagePtr = evaluator.getAllocator().allocate(size + 1); + std::uninitialized_copy(message.begin(), message.end(), messagePtr); + messagePtr[size] = '\0'; + return evaluator.getUnknown( + (SILInstruction *)apply, + UnknownReason::createAssertionFailure(messagePtr, size)); + } case WellKnownFunction::StringInitEmpty: { // String.init() assert(conventions.getNumDirectSILResults() == 1 && conventions.getNumIndirectSILResults() == 0 && @@ -700,16 +775,16 @@ ConstExprFunctionState::computeWellKnownCallResult(ApplyInst *apply, conventions.getNumParameters() == 4 && "unexpected signature"); auto literal = getConstantValue(apply->getOperand(1)); if (literal.getKind() != SymbolicValue::String) { - return evaluator.getUnknown((SILInstruction *)apply, - UnknownReason::InvalidOperandValue); + return getUnknown(evaluator, (SILInstruction *)apply, + UnknownReason::InvalidOperandValue); } auto literalVal = literal.getStringValue(); auto byteCount = getConstantValue(apply->getOperand(2)); if (byteCount.getKind() != SymbolicValue::Integer || byteCount.getIntegerValue().getLimitedValue() != literalVal.size()) { - return evaluator.getUnknown((SILInstruction *)apply, - UnknownReason::InvalidOperandValue); + return getUnknown(evaluator, (SILInstruction *)apply, + UnknownReason::InvalidOperandValue); } setValue(apply, literal); return None; @@ -726,8 +801,8 @@ ConstExprFunctionState::computeWellKnownCallResult(ApplyInst *apply, return otherString; } if (otherString.getKind() != SymbolicValue::String) { - return evaluator.getUnknown((SILInstruction *)apply, - UnknownReason::InvalidOperandValue); + return getUnknown(evaluator, (SILInstruction *)apply, + UnknownReason::InvalidOperandValue); } auto inoutOperand = apply->getOperand(2); @@ -736,8 +811,8 @@ ConstExprFunctionState::computeWellKnownCallResult(ApplyInst *apply, return firstString; } if (firstString.getKind() != SymbolicValue::String) { - return evaluator.getUnknown((SILInstruction *)apply, - UnknownReason::InvalidOperandValue); + return getUnknown(evaluator, (SILInstruction *)apply, + UnknownReason::InvalidOperandValue); } auto result = SmallString<8>(firstString.getStringValue()); @@ -755,14 +830,14 @@ ConstExprFunctionState::computeWellKnownCallResult(ApplyInst *apply, auto firstString = getConstantValue(apply->getOperand(1)); if (firstString.getKind() != SymbolicValue::String) { - return evaluator.getUnknown((SILInstruction *)apply, - UnknownReason::InvalidOperandValue); + return getUnknown(evaluator, (SILInstruction *)apply, + UnknownReason::InvalidOperandValue); } auto otherString = getConstantValue(apply->getOperand(2)); if (otherString.getKind() != SymbolicValue::String) { - return evaluator.getUnknown((SILInstruction *)apply, - UnknownReason::InvalidOperandValue); + return getUnknown(evaluator, (SILInstruction *)apply, + UnknownReason::InvalidOperandValue); } // The result is a Swift.Bool which is a struct that wraps an Int1. @@ -787,8 +862,8 @@ ConstExprFunctionState::computeWellKnownCallResult(ApplyInst *apply, } if (stringArgument.getKind() != SymbolicValue::String) { - return evaluator.getUnknown((SILInstruction *)apply, - UnknownReason::InvalidOperandValue); + return getUnknown(evaluator, (SILInstruction *)apply, + UnknownReason::InvalidOperandValue); } // Replace all precent symbol (%) in the string with double percents (%%) @@ -816,13 +891,11 @@ ConstExprFunctionState::computeWellKnownCallResult(ApplyInst *apply, /// information about the error. llvm::Optional ConstExprFunctionState::computeCallResult(ApplyInst *apply) { - auto conventions = apply->getSubstCalleeConv(); - // Determine the callee. auto calleeFn = getConstantValue(apply->getOperand(0)); if (calleeFn.getKind() != SymbolicValue::Function) - return evaluator.getUnknown((SILInstruction *)apply, - UnknownReason::InvalidOperandValue); + return getUnknown(evaluator, (SILInstruction *)apply, + UnknownReason::InvalidOperandValue); SILFunction *callee = calleeFn.getFunctionValue(); @@ -879,9 +952,8 @@ ConstExprFunctionState::computeCallResult(ApplyInst *apply) { auto conf = protoSelfToConcreteType.lookupConformance( protocol->getSelfInterfaceType()->getCanonicalType(), protocol); if (!conf.hasValue()) - return evaluator.getUnknown( - (SILInstruction *)apply, - UnknownReason::UnknownWitnessMethodConformance); + return getUnknown(evaluator, (SILInstruction *)apply, + UnknownReason::UnknownWitnessMethodConformance); callSubMap = getWitnessMethodSubstitutions( apply->getModule(), ApplySite(apply), callee, conf.getValue()); @@ -906,27 +978,15 @@ ConstExprFunctionState::computeCallResult(ApplyInst *apply) { // Now that we have successfully folded all of the parameters, we can evaluate // the call. evaluator.pushCallStack(apply->getLoc().getSourceLoc()); - SmallVector results; + SymbolicValue result; auto callResult = evaluateAndCacheCall(*callee, calleeSubMap, paramConstants, - results, numInstEvaluated, evaluator); + result, numInstEvaluated, evaluator); evaluator.popCallStack(); + + // Return the error value the callee evaluation failed. if (callResult.hasValue()) return callResult.getValue(); - - unsigned nextResult = 0; - - // If evaluation was successful, remember the results we captured in our - // current function's state. - if (unsigned numNormalResults = conventions.getNumDirectSILResults()) { - // TODO: unclear when this happens, is this for tuple result values? - assert(numNormalResults == 1 && "Multiple results aren't supported?"); - setValue(apply->getResults()[0], results[nextResult]); - ++nextResult; - } - - assert(nextResult == results.size() && "Unexpected number of results found"); - - // We have successfully folded this call! + setValue(apply, result); return None; } @@ -1036,8 +1096,8 @@ ConstExprFunctionState::initializeAddressFromSingleWriter(SILValue addr) { if (use->getOperandNumber() == 1) { // Forbid multiple assignment. if (getMemoryValue().getKind() != SymbolicValue::UninitMemory) - return error(evaluator.getUnknown( - addr, UnknownReason::MutipleTopLevelWriters)); + return error(getUnknown(evaluator, addr, + UnknownReason::MutipleTopLevelWriters)); auto result = getConstantValue(si->getOperand(0)); if (!result.isConstant()) @@ -1058,7 +1118,7 @@ ConstExprFunctionState::initializeAddressFromSingleWriter(SILValue addr) { // Forbid multiple assignment. if (getMemoryValue().getKind() != SymbolicValue::UninitMemory) return error( - evaluator.getUnknown(addr, UnknownReason::MutipleTopLevelWriters)); + getUnknown(evaluator, addr, UnknownReason::MutipleTopLevelWriters)); auto result = getConstAddrAndLoadResult(cai->getOperand(0)); if (!result.isConstant()) @@ -1083,7 +1143,7 @@ ConstExprFunctionState::initializeAddressFromSingleWriter(SILValue addr) { // Forbid multiple assignment. if (getMemoryValue().getKind() != SymbolicValue::UninitMemory) return error( - evaluator.getUnknown(addr, UnknownReason::MutipleTopLevelWriters)); + getUnknown(evaluator, addr, UnknownReason::MutipleTopLevelWriters)); // The callee needs to be a direct call to a constant expression. auto callResult = computeCallResult(apply); @@ -1106,7 +1166,7 @@ ConstExprFunctionState::initializeAddressFromSingleWriter(SILValue addr) { continue; } return error( - evaluator.getUnknown(addr, UnknownReason::NotTopLevelConstant)); + getUnknown(evaluator, addr, UnknownReason::NotTopLevelConstant)); } if (auto *teai = dyn_cast(user)) { @@ -1154,12 +1214,12 @@ ConstExprFunctionState::initializeAddressFromSingleWriter(SILValue addr) { // If this is some other user that we don't know about, then we should // treat it conservatively, because it could store into the address. return error( - evaluator.getUnknown(addr, UnknownReason::NotTopLevelConstant)); + getUnknown(evaluator, addr, UnknownReason::NotTopLevelConstant)); } if (mustCheckAggregateInitialized && !checkAggregateInitialized()) return error( - evaluator.getUnknown(addr, UnknownReason::NotTopLevelConstant)); + getUnknown(evaluator, addr, UnknownReason::NotTopLevelConstant)); return None; } @@ -1209,7 +1269,7 @@ ConstExprFunctionState::getSingleWriterAddressValue(SILValue addr) { assert(addr->getType().isAddress()); auto *addrInst = dyn_cast(addr); if (!addrInst) - return evaluator.getUnknown(addr, UnknownReason::NotTopLevelConstant); + return getUnknown(evaluator, addr, UnknownReason::NotTopLevelConstant); // Create a memory object to initialize, and point `addr` at it. auto memoryAddress = @@ -1223,7 +1283,7 @@ ConstExprFunctionState::getSingleWriterAddressValue(SILValue addr) { } if (!memoryObject->getValue().isConstant()) { auto unknown = - evaluator.getUnknown(addr, UnknownReason::NotTopLevelConstant); + getUnknown(evaluator, addr, UnknownReason::NotTopLevelConstant); memoryObject->setValue(unknown); return unknown; } @@ -1269,7 +1329,7 @@ SymbolicValue ConstExprFunctionState::loadAddrValue(SILValue addr, return objectVal; // Otherwise, return a generic failure. - return evaluator.getUnknown(addr, UnknownReason::InvalidOperandValue); + return getUnknown(evaluator, addr, UnknownReason::InvalidOperandValue); } /// Evaluate a flow sensitive store to the specified pointer address. @@ -1278,9 +1338,9 @@ ConstExprFunctionState::computeFSStore(SymbolicValue storedCst, SILValue dest) { // Only update existing memory locations that we're tracking. auto it = calculatedValues.find(dest); if (it == calculatedValues.end()) - return evaluator.getUnknown(dest, UnknownReason::UntrackedSILValue); + return getUnknown(evaluator, dest, UnknownReason::UntrackedSILValue); if (!it->second.isConstant()) - return evaluator.getUnknown(dest, UnknownReason::InvalidOperandValue); + return getUnknown(evaluator, dest, UnknownReason::InvalidOperandValue); SmallVector accessPath; auto *memoryObject = it->second.getAddressValue(accessPath); @@ -1309,6 +1369,16 @@ ConstExprFunctionState::evaluateFlowSensitive(SILInstruction *inst) { // If this is a special flow-sensitive instruction like a stack allocation, // store, copy_addr, etc, we handle it specially here. if (auto asi = dyn_cast(inst)) { + // If a struct with no stored properties is created, no initialization is + // needed. Hence, create a empty aggregate as the initial value. + StructDecl *structDecl = + asi->getElementType().getStructOrBoundGenericStruct(); + if (structDecl && structDecl->getStoredProperties().empty()) { + createMemoryObject(asi, + SymbolicValue::getAggregate(ArrayRef(), + evaluator.getAllocator())); + return None; + } createMemoryObject(asi, SymbolicValue::getUninitMemory()); return None; } @@ -1334,7 +1404,7 @@ ConstExprFunctionState::evaluateFlowSensitive(SILInstruction *inst) { if (failed.getIntegerValue() == 0) return None; // Conditional fail actually failed. - return evaluator.getUnknown(inst, UnknownReason::Trap); + return getUnknown(evaluator, inst, UnknownReason::Trap); } } @@ -1394,7 +1464,7 @@ ConstExprFunctionState::evaluateFlowSensitive(SILInstruction *inst) { LLVM_DEBUG(llvm::dbgs() << "ConstExpr Unknown FS: " << *inst << "\n"); // If this is an unknown instruction with no results then bail out. - return evaluator.getUnknown(inst, UnknownReason::UnsupportedInstruction); + return getUnknown(evaluator, inst, UnknownReason::UnsupportedInstruction); } std::pair, Optional> @@ -1417,7 +1487,7 @@ ConstExprFunctionState::evaluateInstructionAndGetNext( // If we've already visited this block then fail - we have a loop. if (!visitedBlocks.insert(destBB).second) - return {None, evaluator.getUnknown(br, UnknownReason::Loop)}; + return {None, getUnknown(evaluator, br, UnknownReason::Loop)}; // Set up basic block arguments. for (unsigned i = 0, e = br->getNumArgs(); i != e; ++i) { @@ -1443,7 +1513,7 @@ ConstExprFunctionState::evaluateInstructionAndGetNext( // If we've already visited this block then fail - we have a loop. if (!visitedBlocks.insert(destBB).second) - return {None, evaluator.getUnknown(cbr, UnknownReason::Loop)}; + return {None, getUnknown(evaluator, cbr, UnknownReason::Loop)}; return {destBB->begin(), None}; } @@ -1492,17 +1562,18 @@ ConstExprFunctionState::evaluateInstructionAndGetNext( << "\n"); return {None, - evaluator.getUnknown(inst, UnknownReason::UnsupportedInstruction)}; + getUnknown(evaluator, inst, UnknownReason::UnsupportedInstruction)}; } /// Evaluate a call to the specified function as if it were a constant /// expression, returning None and filling in `results` on success, or /// returning an 'Unknown' SymbolicValue on failure carrying the error. /// -static llvm::Optional evaluateAndCacheCall( - SILFunction &fn, SubstitutionMap substitutionMap, - ArrayRef arguments, SmallVectorImpl &results, - unsigned &numInstEvaluated, ConstExprEvaluator &evaluator) { +static llvm::Optional +evaluateAndCacheCall(SILFunction &fn, SubstitutionMap substitutionMap, + ArrayRef arguments, SymbolicValue &result, + unsigned &numInstEvaluated, + ConstExprEvaluator &evaluator) { assert(!fn.isExternalDeclaration() && "Can't analyze bodyless function"); ConstExprFunctionState state(evaluator, &fn, substitutionMap, numInstEvaluated); @@ -1510,8 +1581,6 @@ static llvm::Optional evaluateAndCacheCall( // TODO: implement caching. // TODO: reject code that is too complex. - // Set up all of the indirect results and argument values. - auto conventions = fn.getConventions(); unsigned nextBBArg = 0; const auto &argList = fn.front().getArguments(); @@ -1538,7 +1607,7 @@ static llvm::Optional evaluateAndCacheCall( // Make sure we haven't exceeded our interpreter iteration cap. if (++numInstEvaluated > ConstExprLimit) { - return evaluator.getUnknown(inst, UnknownReason::TooManyInstructions); + return getUnknown(evaluator, inst, UnknownReason::TooManyInstructions); } if (isa(inst)) { @@ -1548,14 +1617,7 @@ static llvm::Optional evaluateAndCacheCall( // If we got a constant value, then we're good. Set up the normal result // values as well as any indirect results. - auto numNormalResults = conventions.getNumDirectSILResults(); - if (numNormalResults == 1) { - results.push_back(val); - } else if (numNormalResults > 1) { - auto elts = val.getAggregateValue(); - assert(elts.size() == numNormalResults && "result list mismatch!"); - results.append(results.begin(), results.end()); - } + result = val; // TODO: Handle caching of results. @@ -1691,8 +1753,9 @@ ConstExprStepEvaluator::skipByMakingEffectsNonConstant( SmallVector accessPath; auto *memoryObject = constVal.getAddressValue(accessPath); auto unknownValue = SymbolicValue::getUnknown( - inst, UnknownReason::MutatedByUnevaluatedInstruction, {}, - evaluator.getAllocator()); + inst, + UnknownReason::create(UnknownReason::MutatedByUnevaluatedInstruction), + {}, evaluator.getAllocator()); auto memoryContent = memoryObject->getValue(); if (memoryContent.getKind() == SymbolicValue::Aggregate) { @@ -1707,8 +1770,10 @@ ConstExprStepEvaluator::skipByMakingEffectsNonConstant( for (auto result : inst->getResults()) { internalState->setValue( result, SymbolicValue::getUnknown( - inst, UnknownReason::ReturnedByUnevaluatedInstruction, {}, - evaluator.getAllocator())); + inst, + UnknownReason::create( + UnknownReason::ReturnedByUnevaluatedInstruction), + {}, evaluator.getAllocator())); } // If we have a next instruction in the basic block return it. @@ -1724,9 +1789,8 @@ ConstExprStepEvaluator::skipByMakingEffectsNonConstant( bool ConstExprStepEvaluator::isFailStopError(SymbolicValue errorVal) { assert(errorVal.isUnknown()); - switch (errorVal.getUnknownReason()) { + switch (errorVal.getUnknownReason().getKind()) { case UnknownReason::TooManyInstructions: - case UnknownReason::Loop: case UnknownReason::Overflow: case UnknownReason::Trap: return true; @@ -1738,7 +1802,6 @@ bool ConstExprStepEvaluator::isFailStopError(SymbolicValue errorVal) { std::pair, Optional> ConstExprStepEvaluator::tryEvaluateOrElseMakeEffectsNonConstant( SILBasicBlock::iterator instI) { - auto evaluateResult = evaluate(instI); Optional nextI = evaluateResult.first; Optional errorVal = evaluateResult.second; @@ -1753,8 +1816,12 @@ ConstExprStepEvaluator::tryEvaluateOrElseMakeEffectsNonConstant( return evaluateResult; } - // Evaluation cannot fail on unconditional branches. - assert(!isa(&(*instI))); + // If evaluation fails on an unconditional branch, it implies there is a loop + // at the top level. + if (isa(&(*instI))) { + assert(errorVal->getUnknownReason().getKind() == UnknownReason::Loop); + return evaluateResult; + } // Since the evaluation has failed, make the effects of this instruction // unknown. @@ -1771,6 +1838,6 @@ ConstExprStepEvaluator::lookupConstValue(SILValue value) { return res; } -bool ConstExprStepEvaluator::isKnownFunction(SILFunction *fun) { +bool swift::isKnownConstantEvaluableFunction(SILFunction *fun) { return classifyFunction(fun).hasValue(); } diff --git a/test/SILOptimizer/constant_evaluator_test.sil b/test/SILOptimizer/constant_evaluator_test.sil index c29f14b8d8f2f..e0029995a6e01 100644 --- a/test/SILOptimizer/constant_evaluator_test.sil +++ b/test/SILOptimizer/constant_evaluator_test.sil @@ -464,7 +464,7 @@ bb0: // function_ref readLine(strippingNewline:) %2 = function_ref @$ss8readLine16strippingNewlineSSSgSb_tF : $@convention(thin) (Bool) -> @owned Optional %3 = apply %2(%1) : $@convention(thin) (Bool) -> @owned Optional - // CHECK: {{.*}}:[[@LINE-1]]:{{.*}}: note: encountered call to a function whose body is not available + // CHECK: {{.*}}:[[@LINE-1]]:{{.*}}: note: encountered call to 'Swift.readLine(strippingNewline: Swift.Bool) -> Swift.Optional' whose body is not available release_value %3 : $Optional %5 = tuple () return %5 : $() @@ -1152,3 +1152,64 @@ bb0: cond_fail %19 : $Builtin.Int1 return %18 : $Builtin.Int64 } // CHECK: Returns int: 36 + +// Tests for builtin "ptrtoint_Word", which is supported only for string +// constants in order to handle 'StaticString' construction. + +// CHECK-LABEL: @interpretPtrToInt +sil @interpretPtrToInt : $@convention(thin) () -> Builtin.Word { + %0 = string_literal utf8 "Fatal error" + %1 = builtin "ptrtoint_Word"(%0 : $Builtin.RawPointer) : $Builtin.Word + return %1 : $Builtin.Word +} // CHECK: Returns string: "Fatal error" + +// CHECK-LABEL: @interpretStaticStringInit +sil @interpretStaticStringInit : $@convention(thin) () -> Builtin.Word { + %0 = string_literal utf8 "static error message" + %1 = integer_literal $Builtin.Word, 11 + %2 = builtin "ptrtoint_Word"(%0 : $Builtin.RawPointer) : $Builtin.Word + %3 = integer_literal $Builtin.Int8, 2 + %4 = struct $StaticString (%2 : $Builtin.Word, %1 : $Builtin.Word, %3 : $Builtin.Int8) + %5 = struct_extract %4 : $StaticString, #StaticString._startPtrOrData + return %5 : $Builtin.Word +} // CHECK: Returns string: "static error message" + +// Tests for builtin "assert_configuration". Constant evaluator evaluates this +// builtin to 0, meaning that the the configuration is "debug". + +// CHECK-LABEL: @interpretAssertConfiguration +sil @interpretAssertConfiguration : $@convention(thin) () -> Builtin.Int32 { + %0 = builtin "assert_configuration"() : $Builtin.Int32 + return %0 : $Builtin.Int32 +} // CHECK: Returns int: 0 + +// Tests for "assertionFailure" stdlib functions. Such functions have the +// @_semantics attribute: "programtermination_point" + +sil [noinline] [_semantics "programtermination_point"] [canonical] @$assertionFailure : $@convention(thin) (StaticString, StaticString, UInt64) -> Never + +// CHECK-LABEL: @interpretAssertionFailure +sil @interpretAssertionFailure : $@convention(thin) () -> Never { + // Construct error prefix. + %0 = string_literal utf8 "prefix" + %1 = integer_literal $Builtin.Word, 6 + %2 = builtin "ptrtoint_Word"(%0 : $Builtin.RawPointer) : $Builtin.Word + %3 = integer_literal $Builtin.Int8, 2 + %4 = struct $StaticString (%2 : $Builtin.Word, %1 : $Builtin.Word, %3 : $Builtin.Int8) + + // Construct error message. + %10 = string_literal utf8 "message" + %11 = integer_literal $Builtin.Word, 7 + %12 = builtin "ptrtoint_Word"(%10 : $Builtin.RawPointer) : $Builtin.Word + %13 = integer_literal $Builtin.Int8, 2 + %14 = struct $StaticString (%12 : $Builtin.Word, %11 : $Builtin.Word, %13 : $Builtin.Int8) + + // Construct line number. + %20 = integer_literal $Builtin.Int64, 1208 + %21 = struct $UInt64 (%20 : $Builtin.Int64) + + %22 = function_ref @$assertionFailure : $@convention(thin) (StaticString, StaticString, UInt64) -> Never + %23 = apply %22(%4, %14, %21) : $@convention(thin) (StaticString, StaticString, UInt64) -> Never + // CHECK: {{.*}}:[[@LINE-1]]:{{.*}}: note: assertion failed with message: prefix: message: + unreachable +} diff --git a/test/SILOptimizer/pound_assert.swift b/test/SILOptimizer/pound_assert.swift index 6dae20bac625c..d09b59e7c9c82 100644 --- a/test/SILOptimizer/pound_assert.swift +++ b/test/SILOptimizer/pound_assert.swift @@ -1,7 +1,5 @@ // RUN: %target-swift-frontend -enable-experimental-static-assert -emit-sil %s -verify // RUN: %target-swift-frontend -enable-experimental-static-assert -enable-ownership-stripping-after-serialization -emit-sil %s -verify - -// REQUIRES: optimized_stdlib // REQUIRES: asserts //===----------------------------------------------------------------------===// @@ -39,7 +37,6 @@ func loops1(a: Int) -> Int { func loops2(a: Int) -> Int { var x = 42 - // expected-note @+1 {{operation not supported by the evaluator}} for i in 0 ... a { x += i } From 30f5269670f7816b30a8aac695f3de2e5fcb6d84 Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Mon, 16 Sep 2019 14:03:17 -0700 Subject: [PATCH 031/199] IRGen: Use correct generic sig when mangling opaque underlying type. Caught while testing on Swift 5.1. --- lib/IRGen/GenMeta.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 133fea5660c13..0822d305404e5 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -1683,14 +1683,16 @@ namespace { } void addUnderlyingTypeAndConformances() { - auto sig = O->getOpaqueInterfaceGenericSignature() - ? O->getOpaqueInterfaceGenericSignature()->getCanonicalSignature() - : CanGenericSignature(); + auto sig = O->getOpaqueInterfaceGenericSignature(); auto underlyingType = Type(O->getUnderlyingInterfaceType()) .subst(*O->getUnderlyingTypeSubstitutions()) ->getCanonicalType(sig); + + auto contextSig = O->getGenericSignature() + ? O->getGenericSignature()->getCanonicalSignature() + : CanGenericSignature(); - B.addRelativeAddress(IGM.getTypeRef(underlyingType, sig, + B.addRelativeAddress(IGM.getTypeRef(underlyingType, contextSig, MangledTypeRefRole::Metadata).first); auto opaqueType = O->getDeclaredInterfaceType() @@ -1704,7 +1706,7 @@ namespace { auto witnessTableRef = IGM.emitWitnessTableRefString( underlyingType, underlyingConformance, - O->getGenericSignature(), + contextSig, /*setLowBit*/ false); B.addRelativeAddress(witnessTableRef); } From 8912ef9fd01d40287a17b213e96d583ff7386769 Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Mon, 16 Sep 2019 12:03:03 -0700 Subject: [PATCH 032/199] ABI/API checker: move node mapping information from under -v to under -debug. NFC --- tools/swift-api-digester/swift-api-digester.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp index d5969a8540a04..f22e4cd806ee7 100644 --- a/tools/swift-api-digester/swift-api-digester.cpp +++ b/tools/swift-api-digester/swift-api-digester.cpp @@ -130,6 +130,10 @@ static llvm::cl::opt Verbose("v", llvm::cl::desc("Verbose"), llvm::cl::cat(Category)); +static llvm::cl::opt +DebugMapping("debug-mapping", llvm::cl::desc("Dumping information for debug purposes"), + llvm::cl::cat(Category)); + static llvm::cl::opt Abi("abi", llvm::cl::desc("Dumping ABI interface"), llvm::cl::init(false), llvm::cl::cat(Category)); @@ -1090,7 +1094,7 @@ class PrunePass : public MatchedNodeListener, public SDKTreeDiffPass { ProtocolReqWhitelist(std::move(prWhitelist)) {} void foundMatch(NodePtr Left, NodePtr Right, NodeMatchReason Reason) override { - if (options::Verbose) + if (options::DebugMapping) debugMatch(Left, Right, Reason, llvm::errs()); switch (Reason) { case NodeMatchReason::Added: From c4f448578ed444f40cb5407cf0aa1c9bd29dcb25 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Mon, 16 Sep 2019 15:29:39 -0700 Subject: [PATCH 033/199] Revert "runtime: add a workaround for Windows build" This reverts commit efaf1fbefa7fc94ff535b35b964689735637458b. Add a much more palatable workaround for the unit tests. Rather than adding the dllimport for the symbols, locally define the required symbols. This list is sufficient to restore the ability to build tests for Windows. --- stdlib/public/runtime/MetadataLookup.cpp | 8 +- unittests/runtime/Stdlib.cpp | 215 +++++++++++++++++++++++ 2 files changed, 216 insertions(+), 7 deletions(-) diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp index 76f52aeb175d0..bc307b6ce15e5 100644 --- a/stdlib/public/runtime/MetadataLookup.cpp +++ b/stdlib/public/runtime/MetadataLookup.cpp @@ -730,14 +730,8 @@ _findContextDescriptorInCache(TypeMetadataPrivateState &T, $sS ## CHAR ## SUFFIX #define DESCRIPTOR_MANGLING(CHAR, SUFFIX) DESCRIPTOR_MANGLING_(CHAR, SUFFIX) -#if defined(_WIN32) -#define swiftCore_EXPORTS __declspec(dllimport) -#else -#define swiftCore_EXPORTS -#endif - #define STANDARD_TYPE(KIND, MANGLING, TYPENAME) \ - extern "C" swiftCore_EXPORTS const ContextDescriptor DESCRIPTOR_MANGLING(MANGLING, DESCRIPTOR_MANGLING_SUFFIX(KIND)); + extern "C" const ContextDescriptor DESCRIPTOR_MANGLING(MANGLING, DESCRIPTOR_MANGLING_SUFFIX(KIND)); #if !SWIFT_OBJC_INTEROP # define OBJC_INTEROP_STANDARD_TYPE(KIND, MANGLING, TYPENAME) diff --git a/unittests/runtime/Stdlib.cpp b/unittests/runtime/Stdlib.cpp index 1d356f20fd5dc..0c257e14bc167 100644 --- a/unittests/runtime/Stdlib.cpp +++ b/unittests/runtime/Stdlib.cpp @@ -204,6 +204,221 @@ const long long $ssSeVMn[1] = {0}; SWIFT_RUNTIME_STDLIB_INTERNAL const long long $sShMn[1] = {0}; +// Bool + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSbMn[1] = {0}; + +// Binary Floating Point + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSBMp[1] = {0}; + +// Double + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSdMn[1] = {0}; + +// RandomNumberGenerator + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSGMp[1] = {0}; + +// Int + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSiMn[1] = {0}; + +// DefaultIndicis + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSIMn[1] = {0}; + +// Character + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSJMn[1] = {0}; + +// Numeric + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSjMp[1] = {0}; + +// RandomAccessCollection + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSkMp[1] = {0}; + +// BidirectionalCollection + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSKMp[1] = {0}; + +// RangeReplacementCollection + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSmMp[1] = {0}; + +// MutationCollection + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSMMp[1] = {0}; + +// Range + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSnMn[1] = {0}; + +// ClosedRange + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSNMn[1] = {0}; + +// ObjectIdentifier + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSOMn[1] = {0}; + +// UnsafeMutablePointer + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSpMn[1] = {0}; + +// Optional + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSqMn[1] = {0}; + +// Equatable + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSQMp[1] = {0}; + +// UnsafeMutableBufferPointer + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSrMn[1] = {0}; + +// UnsafeBufferPointer + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSRMn[1] = {0}; + +// String + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSSMn[1] = {0}; + +// Sequence + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSTMp[1] = {0}; + +// UInt + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSuMn[1] = {0}; + +// UnsignedInteger + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSUMp[1] = {0}; + +// UnsafeMutableRawPointer + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSvMn[1] = {0}; + +// Strideable + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSxMp[1] = {0}; + +// RangeExpression + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSXMp[1] = {0}; + +// StringProtocol + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSyMp[1] = {0}; + +// RawRepresentable + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSYMp[1] = {0}; + +// BinaryInteger + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSzMp[1] = {0}; + +// Decodable + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSeMp[1] = {0}; + +// Encodable + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSEMp[1] = {0}; + +// Float + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSfMn[1] = {0}; + +// FloatingPoint + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSFMp[1] = {0}; + +// Collection + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSlMp[1] = {0}; + +// Comparable + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSLMp[1] = {0}; + +// UnsafePointer + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSPMn[1] = {0}; + +// Substring + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSsMn[1] = {0}; + +// IteratorProtocol + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sStMp[1] = {0}; + +// UnsafeRawPointer + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSVMn[1] = {0}; + +// UnsafeMutableRawBufferPointer + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSwMn[1] = {0}; + +// UnsafeRawBufferPointer + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSWMn[1] = {0}; + +// SignedInteger + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSZMp[1] = {0}; + // Mirror // protocol witness table for Swift._ClassSuperMirror : Swift._Mirror in Swift From 2f325fa1d8515b42ff02bc53962b9e0bd87ac143 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 16 Sep 2019 16:47:09 -0700 Subject: [PATCH 034/199] [Diagnostics] Don't store contextual type in missing argument fix/diagnostic Instead of storing contextual function type in the fix/diagnostic, let's fetch it from context (solution and/or locator) because it's only used when it is a trailing closure missing some arguments anyway. --- lib/Sema/CSDiag.cpp | 2 +- lib/Sema/CSDiagnostics.cpp | 25 +++++++++++++++++++------ lib/Sema/CSDiagnostics.h | 8 ++------ lib/Sema/CSFix.cpp | 8 ++++---- lib/Sema/CSFix.h | 9 ++++----- lib/Sema/CSSimplify.cpp | 18 +++++++----------- 6 files changed, 37 insertions(+), 33 deletions(-) diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp index 631280e623a9a..737ec7beabeb9 100644 --- a/lib/Sema/CSDiag.cpp +++ b/lib/Sema/CSDiag.cpp @@ -4092,7 +4092,7 @@ bool FailureDiagnosis::diagnoseClosureExpr( } MissingArgumentsFailure failure( - expr, CS, fnType, inferredArgCount - actualArgCount, + expr, CS, inferredArgCount - actualArgCount, CS.getConstraintLocator(CE, LocatorPathElt::ContextualType())); return failure.diagnoseAsError(); } diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 5aaa7b8bb9b21..8c68c66e0d6f6 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -3511,7 +3511,20 @@ bool MissingArgumentsFailure::diagnoseAsError() { } bool MissingArgumentsFailure::diagnoseTrailingClosure(ClosureExpr *closure) { - auto diff = Fn->getNumParams() - NumSynthesized; + auto &cs = getConstraintSystem(); + FunctionType *funcType = nullptr; + + auto *locator = getLocator(); + if (locator->isForContextualType()) { + funcType = cs.getContextualType()->getAs(); + } else if (auto info = getFunctionArgApplyInfo(locator)) { + funcType = info->getParamType()->getAs(); + } + + if (!funcType) + return false; + + auto diff = funcType->getNumParams() - NumSynthesized; // If the closure didn't specify any arguments and it is in a context that // needs some, produce a fixit to turn "{...}" into "{ _,_ in ...}". @@ -3521,10 +3534,10 @@ bool MissingArgumentsFailure::diagnoseTrailingClosure(ClosureExpr *closure) { diag::closure_argument_list_missing, NumSynthesized); std::string fixText; // Let's provide fixits for up to 10 args. - if (Fn->getNumParams() <= 10) { + if (funcType->getNumParams() <= 10) { fixText += " "; interleave( - Fn->getParams(), + funcType->getParams(), [&fixText](const AnyFunctionType::Param ¶m) { fixText += '_'; }, [&fixText] { fixText += ','; }); fixText += " in "; @@ -3550,9 +3563,9 @@ bool MissingArgumentsFailure::diagnoseTrailingClosure(ClosureExpr *closure) { std::all_of(params->begin(), params->end(), [](ParamDecl *param) { return !param->hasName(); }); - auto diag = - emitDiagnostic(params->getStartLoc(), diag::closure_argument_list_tuple, - resolveType(Fn), Fn->getNumParams(), diff, diff == 1); + auto diag = emitDiagnostic( + params->getStartLoc(), diag::closure_argument_list_tuple, + resolveType(funcType), funcType->getNumParams(), diff, diff == 1); // If the number of parameters is less than number of inferred // let's try to suggest a fix-it with the rest of the missing parameters. diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 264f2020ca790..49ec8dcb50416 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -1182,16 +1182,12 @@ class ImplicitInitOnNonConstMetatypeFailure final class MissingArgumentsFailure final : public FailureDiagnostic { using Param = AnyFunctionType::Param; - FunctionType *Fn; unsigned NumSynthesized; public: MissingArgumentsFailure(Expr *root, ConstraintSystem &cs, - FunctionType *funcType, - unsigned numSynthesized, - ConstraintLocator *locator) - : FailureDiagnostic(root, cs, locator), Fn(funcType), - NumSynthesized(numSynthesized) {} + unsigned numSynthesized, ConstraintLocator *locator) + : FailureDiagnostic(root, cs, locator), NumSynthesized(numSynthesized) {} bool diagnoseAsError() override; diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index c351ce41b2035..76b21b842dc1f 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -477,18 +477,18 @@ AllowClosureParamDestructuring::create(ConstraintSystem &cs, } bool AddMissingArguments::diagnose(Expr *root, bool asNote) const { - MissingArgumentsFailure failure(root, getConstraintSystem(), Fn, - NumSynthesized, getLocator()); + auto &cs = getConstraintSystem(); + MissingArgumentsFailure failure(root, cs, NumSynthesized, getLocator()); return failure.diagnose(asNote); } AddMissingArguments * -AddMissingArguments::create(ConstraintSystem &cs, FunctionType *funcType, +AddMissingArguments::create(ConstraintSystem &cs, llvm::ArrayRef synthesizedArgs, ConstraintLocator *locator) { unsigned size = totalSizeToAlloc(synthesizedArgs.size()); void *mem = cs.getAllocator().Allocate(size, alignof(AddMissingArguments)); - return new (mem) AddMissingArguments(cs, funcType, synthesizedArgs, locator); + return new (mem) AddMissingArguments(cs, synthesizedArgs, locator); } bool MoveOutOfOrderArgument::diagnose(Expr *root, bool asNote) const { diff --git a/lib/Sema/CSFix.h b/lib/Sema/CSFix.h index bb86cac4d713b..3aadee4d3d00e 100644 --- a/lib/Sema/CSFix.h +++ b/lib/Sema/CSFix.h @@ -1001,13 +1001,12 @@ class AddMissingArguments final using Param = AnyFunctionType::Param; - FunctionType *Fn; unsigned NumSynthesized; - AddMissingArguments(ConstraintSystem &cs, FunctionType *funcType, - llvm::ArrayRef synthesizedArgs, + AddMissingArguments(ConstraintSystem &cs, + llvm::ArrayRef synthesizedArgs, ConstraintLocator *locator) - : ConstraintFix(cs, FixKind::AddMissingArguments, locator), Fn(funcType), + : ConstraintFix(cs, FixKind::AddMissingArguments, locator), NumSynthesized(synthesizedArgs.size()) { std::uninitialized_copy(synthesizedArgs.begin(), synthesizedArgs.end(), getSynthesizedArgumentsBuf().begin()); @@ -1022,7 +1021,7 @@ class AddMissingArguments final bool diagnose(Expr *root, bool asNote = false) const override; - static AddMissingArguments *create(ConstraintSystem &cs, FunctionType *fnType, + static AddMissingArguments *create(ConstraintSystem &cs, llvm::ArrayRef synthesizedArgs, ConstraintLocator *locator); diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 92bf2ec2b5144..d21eece744462 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -1167,9 +1167,8 @@ static ConstraintFix *fixRequirementFailure(ConstraintSystem &cs, Type type1, /// Attempt to fix missing arguments by introducing type variables /// and inferring their types from parameters. static bool fixMissingArguments(ConstraintSystem &cs, Expr *anchor, - FunctionType *funcType, SmallVectorImpl &args, - SmallVectorImpl ¶ms, + ArrayRef params, unsigned numMissing, ConstraintLocatorBuilder locator) { assert(args.size() < params.size()); @@ -1219,9 +1218,8 @@ static bool fixMissingArguments(ConstraintSystem &cs, Expr *anchor, } ArrayRef argsRef(args); - auto *fix = - AddMissingArguments::create(cs, funcType, argsRef.take_back(numMissing), - cs.getConstraintLocator(locator)); + auto *fix = AddMissingArguments::create(cs, argsRef.take_back(numMissing), + cs.getConstraintLocator(locator)); if (cs.recordFix(fix)) return true; @@ -1459,7 +1457,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2, // If there are missing arguments, let's add them // using parameter as a template. if (diff < 0) { - if (fixMissingArguments(*this, anchor, func2, func1Params, func2Params, + if (fixMissingArguments(*this, anchor, func1Params, func2Params, abs(diff), locator)) return getTypeMatchFailure(argumentLocator); } else { @@ -2662,11 +2660,9 @@ bool ConstraintSystem::repairFailures( // But if `T.Element` didn't get resolved to `Void` we'd like // to diagnose this as a missing argument which can't be ignored. if (arg != getTypeVariables().end()) { - auto fnType = FunctionType::get({FunctionType::Param(lhs)}, - getASTContext().TheEmptyTupleType); - conversionsOrFixes.push_back(AddMissingArguments::create( - *this, fnType, {FunctionType::Param(*arg)}, - getConstraintLocator(anchor, path))); + conversionsOrFixes.push_back( + AddMissingArguments::create(*this, {FunctionType::Param(*arg)}, + getConstraintLocator(anchor, path))); } if ((lhs->is() && !rhs->is()) || From 7ff3fd1f66f9f538399f842e74c1fcc6b34fb41b Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Tue, 17 Sep 2019 00:51:54 +0100 Subject: [PATCH 035/199] [Test] Adds some tests --- test/decl/var/property_wrappers.swift | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/decl/var/property_wrappers.swift b/test/decl/var/property_wrappers.swift index bce415163d7b9..91259b3bd2e25 100644 --- a/test/decl/var/property_wrappers.swift +++ b/test/decl/var/property_wrappers.swift @@ -1644,3 +1644,22 @@ struct UseNonMutatingProjectedValueSet { x = 42 // expected-error{{cannot assign to property: 'self' is immutable}} } } + +// SR-11478 + +@propertyWrapper +struct SR_11478_W { + var wrappedValue: Value +} + +class SR_11478_C1 { + @SR_11478_W static var bool1: Bool = true // Ok + @SR_11478_W class var bool2: Bool = true // expected-error {{class stored properties not supported in classes; did you mean 'static'?}} + @SR_11478_W class final var bool3: Bool = true // expected-error {{class stored properties not supported in classes; did you mean 'static'?}} +} + +final class SR_11478_C2 { + @SR_11478_W static var bool1: Bool = true // Ok + @SR_11478_W class var bool2: Bool = true // expected-error {{class stored properties not supported in classes; did you mean 'static'?}} + @SR_11478_W class final var bool3: Bool = true // expected-error {{class stored properties not supported in classes; did you mean 'static'?}} +} From 0d66b0c5df9f1050d3196f87b2aa000493967720 Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Tue, 17 Sep 2019 01:24:02 +0100 Subject: [PATCH 036/199] [AST] Fix indenation in hasValueSemantics() --- lib/AST/DeclContext.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index 4085edbe3fca3..ff0fe6f528949 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -1025,8 +1025,8 @@ DeclContextKind DeclContext::getContextKind() const { } bool DeclContext::hasValueSemantics() const { - if (!isTypeContext()) - return false; + if (!isTypeContext()) + return false; if (auto contextTy = getSelfTypeInContext()) { return !contextTy->hasReferenceSemantics(); From 5a86d42c1e4b3f51e8fe612c9a62229ff2080fd0 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Mon, 16 Sep 2019 11:03:31 -0700 Subject: [PATCH 037/199] [gardening] Clean up BranchPropagatedUser. --- include/swift/SIL/BranchPropagatedUser.h | 55 ++++++++++++------------ 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/include/swift/SIL/BranchPropagatedUser.h b/include/swift/SIL/BranchPropagatedUser.h index c726693200620..7558cfba620be 100644 --- a/include/swift/SIL/BranchPropagatedUser.h +++ b/include/swift/SIL/BranchPropagatedUser.h @@ -13,6 +13,7 @@ #ifndef SWIFT_SIL_BRANCHPROPAGATEDUSER_H #define SWIFT_SIL_BRANCHPROPAGATEDUSER_H +#include "swift/Basic/LLVM.h" #include "swift/SIL/SILBasicBlock.h" #include "swift/SIL/SILInstruction.h" #include "llvm/ADT/DenseMap.h" @@ -27,68 +28,68 @@ namespace swift { /// BranchPropagatedUser and friends break all such critical edges. class BranchPropagatedUser { using InnerTy = llvm::PointerIntPair; - InnerTy User; + InnerTy user; public: - BranchPropagatedUser(SILInstruction *I) : User(I) { - assert(!isa(I)); + BranchPropagatedUser(SILInstruction *inst) : user(inst) { + assert(!isa(inst)); } - BranchPropagatedUser(CondBranchInst *I) : User(I) {} + BranchPropagatedUser(CondBranchInst *cbi) : user(cbi) {} - BranchPropagatedUser(CondBranchInst *I, unsigned SuccessorIndex) - : User(I, SuccessorIndex) { - assert(SuccessorIndex == CondBranchInst::TrueIdx || - SuccessorIndex == CondBranchInst::FalseIdx); + BranchPropagatedUser(CondBranchInst *cbi, unsigned successorIndex) + : user(cbi, successorIndex) { + assert(successorIndex == CondBranchInst::TrueIdx || + successorIndex == CondBranchInst::FalseIdx); } - BranchPropagatedUser(const BranchPropagatedUser &Other) : User(Other.User) {} - BranchPropagatedUser &operator=(const BranchPropagatedUser &Other) { - User = Other.User; + BranchPropagatedUser(const BranchPropagatedUser &other) : user(other.user) {} + BranchPropagatedUser &operator=(const BranchPropagatedUser &other) { + user = other.user; return *this; } - operator SILInstruction *() { return User.getPointer(); } - operator const SILInstruction *() const { return User.getPointer(); } + operator SILInstruction *() { return user.getPointer(); } + operator const SILInstruction *() const { return user.getPointer(); } - SILInstruction *getInst() const { return User.getPointer(); } + SILInstruction *getInst() const { return user.getPointer(); } SILBasicBlock *getParent() const { if (!isCondBranchUser()) { return getInst()->getParent(); } - auto *CBI = cast(getInst()); - unsigned Number = getCondBranchSuccessorID(); - if (Number == CondBranchInst::TrueIdx) - return CBI->getTrueBB(); - return CBI->getFalseBB(); + auto *cbi = cast(getInst()); + unsigned number = getCondBranchSuccessorID(); + if (number == CondBranchInst::TrueIdx) + return cbi->getTrueBB(); + return cbi->getFalseBB(); } bool isCondBranchUser() const { - return isa(User.getPointer()); + return isa(user.getPointer()); } unsigned getCondBranchSuccessorID() const { assert(isCondBranchUser()); - return User.getInt(); + return user.getInt(); } SILBasicBlock::iterator getIterator() const { - return User.getPointer()->getIterator(); + return user.getPointer()->getIterator(); } void *getAsOpaqueValue() const { - return llvm::PointerLikeTypeTraits::getAsVoidPointer(User); + return llvm::PointerLikeTypeTraits::getAsVoidPointer(user); } static BranchPropagatedUser getFromOpaqueValue(void *p) { - InnerTy TmpUser = + InnerTy tmpUser = llvm::PointerLikeTypeTraits::getFromVoidPointer(p); - if (auto *CBI = dyn_cast(TmpUser.getPointer())) { - return BranchPropagatedUser(CBI, TmpUser.getInt()); + if (auto *cbi = dyn_cast(tmpUser.getPointer())) { + return BranchPropagatedUser(cbi, tmpUser.getInt()); } - return BranchPropagatedUser(TmpUser.getPointer()); + return BranchPropagatedUser(tmpUser.getPointer()); } enum { From 032442da93c33b08e9ea55d876d7e1c30debe598 Mon Sep 17 00:00:00 2001 From: Ravi Kandhadai Date: Mon, 16 Sep 2019 14:54:48 -0700 Subject: [PATCH 038/199] [Constant Evaluator] Add a new sil-opt pass to check constant evaluability of Swift code snippets. Add a new test: constant_evaluable_subset_test.swift that tests Swift code snippets that are expected to be constant evaluable and those that are not. --- .../swift/SILOptimizer/PassManager/Passes.def | 2 + include/swift/SILOptimizer/Utils/ConstExpr.h | 39 +- lib/SILOptimizer/UtilityPasses/CMakeLists.txt | 1 + .../ConstantEvaluableSubsetChecker.cpp | 156 ++++ lib/SILOptimizer/Utils/ConstExpr.cpp | 21 +- .../constant_evaluable_subset_test.swift | 695 ++++++++++++++++++ ...onstant_evaluable_subset_test_arch32.swift | 102 +++ ...onstant_evaluable_subset_test_arch64.swift | 109 +++ 8 files changed, 1108 insertions(+), 17 deletions(-) create mode 100644 lib/SILOptimizer/UtilityPasses/ConstantEvaluableSubsetChecker.cpp create mode 100644 test/SILOptimizer/constant_evaluable_subset_test.swift create mode 100644 test/SILOptimizer/constant_evaluable_subset_test_arch32.swift create mode 100644 test/SILOptimizer/constant_evaluable_subset_test_arch64.swift diff --git a/include/swift/SILOptimizer/PassManager/Passes.def b/include/swift/SILOptimizer/PassManager/Passes.def index 66cb06d0f3903..9a5a210178fb2 100644 --- a/include/swift/SILOptimizer/PassManager/Passes.def +++ b/include/swift/SILOptimizer/PassManager/Passes.def @@ -112,6 +112,8 @@ PASS(ConditionForwarding, "condition-forwarding", "Conditional Branch Forwarding to Fold SIL switch_enum") PASS(ConstantEvaluatorTester, "test-constant-evaluator", "Test constant evaluator") +PASS(ConstantEvaluableSubsetChecker, "test-constant-evaluable-subset", + "Test Swift code snippets expected to be constant evaluable") PASS(CopyForwarding, "copy-forwarding", "Copy Forwarding to Remove Redundant Copies") PASS(CopyPropagation, "copy-propagation", diff --git a/include/swift/SILOptimizer/Utils/ConstExpr.h b/include/swift/SILOptimizer/Utils/ConstExpr.h index cfe04cdb164a6..0f1437ff08f6e 100644 --- a/include/swift/SILOptimizer/Utils/ConstExpr.h +++ b/include/swift/SILOptimizer/Utils/ConstExpr.h @@ -48,10 +48,17 @@ class ConstExprEvaluator { /// The current call stack, used for providing accurate diagnostics. llvm::SmallVector callStack; + /// When set to true, keep track of all functions called during an evaluation. + bool trackCallees; + /// Functions called during the evaluation. This is an auxiliary information + /// provided to the clients. + llvm::SmallPtrSet calledFunctions; + void operator=(const ConstExprEvaluator &) = delete; public: - explicit ConstExprEvaluator(SymbolicValueAllocator &alloc); + explicit ConstExprEvaluator(SymbolicValueAllocator &alloc, + bool trackCallees = false); ~ConstExprEvaluator(); explicit ConstExprEvaluator(const ConstExprEvaluator &other); @@ -75,12 +82,23 @@ class ConstExprEvaluator { /// This is done in code that is not necessarily itself a constexpr /// function. The results are added to the results list which is a parallel /// structure to the input values. - /// - /// TODO: Return information about which callees were found to be - /// constexprs, which would allow the caller to delete dead calls to them - /// that occur after after folding them. void computeConstantValues(ArrayRef values, SmallVectorImpl &results); + + void recordCalledFunctionIfEnabled(SILFunction *callee) { + if (trackCallees) { + calledFunctions.insert(callee); + } + } + + /// If the evaluator was initialized with \c trackCallees enabled, return the + /// SIL functions encountered during the evaluations performed with this + /// evaluator. The returned functions include those that were called but + /// failed to complete successfully. + const SmallPtrSetImpl &getFuncsCalledDuringEvaluation() const { + assert(trackCallees && "evaluator not configured to track callees"); + return calledFunctions; + } }; /// A constant-expression evaluator that can be used to step through a control @@ -106,7 +124,7 @@ class ConstExprStepEvaluator { /// Constructs a step evaluator given an allocator and a non-null pointer to a /// SILFunction. explicit ConstExprStepEvaluator(SymbolicValueAllocator &alloc, - SILFunction *fun); + SILFunction *fun, bool trackCallees = false); ~ConstExprStepEvaluator(); /// Evaluate an instruction in the current interpreter state. @@ -173,6 +191,15 @@ class ConstExprStepEvaluator { /// Note that 'skipByMakingEffectsNonConstant' operation is not considered /// as an evaluation. unsigned instructionsEvaluatedByLastEvaluation() { return stepsEvaluated; } + + /// If the evaluator was initialized with \c trackCallees enabled, return the + /// SIL functions encountered during the evaluations performed with this + /// evaluator. The returned functions include those that were called but + /// failed to complete successfully. Targets of skipped apply instructions + /// will not be included in the returned set. + const SmallPtrSetImpl &getFuncsCalledDuringEvaluation() { + return evaluator.getFuncsCalledDuringEvaluation(); + } }; bool isKnownConstantEvaluableFunction(SILFunction *fun); diff --git a/lib/SILOptimizer/UtilityPasses/CMakeLists.txt b/lib/SILOptimizer/UtilityPasses/CMakeLists.txt index 31887874dd4d9..c33fb8245cb25 100644 --- a/lib/SILOptimizer/UtilityPasses/CMakeLists.txt +++ b/lib/SILOptimizer/UtilityPasses/CMakeLists.txt @@ -10,6 +10,7 @@ silopt_register_sources( ComputeDominanceInfo.cpp ComputeLoopInfo.cpp ConstantEvaluatorTester.cpp + ConstantEvaluableSubsetChecker.cpp EpilogueARCMatcherDumper.cpp EpilogueRetainReleaseMatcherDumper.cpp EscapeAnalysisDumper.cpp diff --git a/lib/SILOptimizer/UtilityPasses/ConstantEvaluableSubsetChecker.cpp b/lib/SILOptimizer/UtilityPasses/ConstantEvaluableSubsetChecker.cpp new file mode 100644 index 0000000000000..953877c292668 --- /dev/null +++ b/lib/SILOptimizer/UtilityPasses/ConstantEvaluableSubsetChecker.cpp @@ -0,0 +1,156 @@ +//===--ConstantEvaluableSubsetChecker.cpp - Test Constant Evaluable Swift--===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +// This file implements a pass for checking the constant evaluability of Swift +// code snippets. This pass is only used in tests and is not part of the +// compilation pipeline. + +#define DEBUG_TYPE "sil-constant-evaluable-subset-checker" +#include "swift/AST/DiagnosticsSIL.h" +#include "swift/AST/Module.h" +#include "swift/Demangling/Demangle.h" +#include "swift/SIL/CFG.h" +#include "swift/SIL/SILConstants.h" +#include "swift/SIL/SILInstruction.h" +#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/ConstExpr.h" + +using namespace swift; + +namespace { + +static const StringRef constantEvaluableSemanticsAttr = "constant_evaluable"; +static const StringRef testDriverSemanticsAttr = "test_driver"; + +template +static InFlightDiagnostic diagnose(ASTContext &Context, SourceLoc loc, + Diag diag, U &&... args) { + return Context.Diags.diagnose(loc, diag, std::forward(args)...); +} + +static std::string demangleSymbolName(StringRef name) { + Demangle::DemangleOptions options; + options.QualifyEntities = false; + return Demangle::demangleSymbolAsString(name, options); +} + +/// A SILModule pass that invokes the constant evaluator on all functions in a +/// SILModule with the semantics attribute "test_driver". Each "test_driver" +/// must invoke one or more functions in the module annotated as +/// "constant_evaluable" with constant arguments. +class ConstantEvaluableSubsetChecker : public SILModuleTransform { + + llvm::SmallPtrSet constantEvaluableFunctions; + llvm::SmallPtrSet evaluatedFunctions; + + /// Evaluate the body of \c fun with the constant evaluator. \c fun must be + /// annotated as "test_driver" and must invoke one or more functions annotated + /// as "constant_evaluable" with constant arguments. Emit diagnostics if the + /// evaluation of any "constant_evaluable" function called in the body of + /// \c fun fails. + void constantEvaluateDriver(SILFunction *fun) { + ASTContext &astContext = fun->getASTContext(); + + // Create a step evaluator and run it on the function. + SymbolicValueBumpAllocator allocator; + ConstExprStepEvaluator stepEvaluator(allocator, fun, + /*trackCallees*/ true); + + for (auto currI = fun->getEntryBlock()->begin();;) { + auto *inst = &(*currI); + + if (isa(inst)) + break; + + auto *applyInst = dyn_cast(inst); + SILFunction *callee = nullptr; + if (applyInst) { + callee = applyInst->getReferencedFunctionOrNull(); + } + + Optional nextInstOpt; + Optional errorVal; + + if (!applyInst || !callee || + !callee->hasSemanticsAttr(constantEvaluableSemanticsAttr)) { + std::tie(nextInstOpt, errorVal) = + stepEvaluator.tryEvaluateOrElseMakeEffectsNonConstant(currI); + assert(nextInstOpt && "non-constant control flow in the test driver"); + currI = nextInstOpt.getValue(); + continue; + } + + // Here, a function annotated as "constant_evaluable" is called. + llvm::errs() << "@" << demangleSymbolName(callee->getName()) << "\n"; + std::tie(nextInstOpt, errorVal) = + stepEvaluator.tryEvaluateOrElseMakeEffectsNonConstant(currI); + + if (errorVal) { + SourceLoc instLoc = inst->getLoc().getSourceLoc(); + diagnose(astContext, instLoc, diag::not_constant_evaluable); + errorVal->emitUnknownDiagnosticNotes(inst->getLoc()); + } + + if (!nextInstOpt) { + break; // This instruction should be the end of the test driver. + } + currI = nextInstOpt.getValue(); + } + + // Record functions that were called during this evaluation to detect + // whether the test drivers in the SILModule cover all function annotated + // as "constant_evaluable". + for (SILFunction *callee : stepEvaluator.getFuncsCalledDuringEvaluation()) { + evaluatedFunctions.insert(callee); + } + } + + void run() override { + SILModule *module = getModule(); + assert(module); + + for (SILFunction &fun : *module) { + // Record functions annotated as constant evaluable. + if (fun.hasSemanticsAttr(constantEvaluableSemanticsAttr)) { + constantEvaluableFunctions.insert(&fun); + continue; + } + + // Evaluate test drivers. + if (!fun.hasSemanticsAttr(testDriverSemanticsAttr)) + continue; + constantEvaluateDriver(&fun); + } + + // Assert that every function annotated as "constant_evaluable" was convered + // by a test driver. + bool error = false; + for (SILFunction *constEvalFun : constantEvaluableFunctions) { + if (!evaluatedFunctions.count(constEvalFun)) { + llvm::errs() << "Error: function " + << demangleSymbolName(constEvalFun->getName()); + llvm::errs() << " annotated as constant evaluable"; + llvm::errs() << " does not have a test driver" + << "\n"; + error = true; + } + } + assert(!error); + } +}; + +} // end anonymous namespace + +SILTransform *swift::createConstantEvaluableSubsetChecker() { + return new ConstantEvaluableSubsetChecker(); +} diff --git a/lib/SILOptimizer/Utils/ConstExpr.cpp b/lib/SILOptimizer/Utils/ConstExpr.cpp index 329179569c719..ecc0677436ee7 100644 --- a/lib/SILOptimizer/Utils/ConstExpr.cpp +++ b/lib/SILOptimizer/Utils/ConstExpr.cpp @@ -898,6 +898,7 @@ ConstExprFunctionState::computeCallResult(ApplyInst *apply) { UnknownReason::InvalidOperandValue); SILFunction *callee = calleeFn.getFunctionValue(); + evaluator.recordCalledFunctionIfEnabled(callee); // If this is a well-known function, do not step into it. if (auto wellKnownFunction = classifyFunction(callee)) @@ -1644,8 +1645,9 @@ evaluateAndCacheCall(SILFunction &fn, SubstitutionMap substitutionMap, // ConstExprEvaluator implementation. //===----------------------------------------------------------------------===// -ConstExprEvaluator::ConstExprEvaluator(SymbolicValueAllocator &alloc) - : allocator(alloc) {} +ConstExprEvaluator::ConstExprEvaluator(SymbolicValueAllocator &alloc, + bool trackCallees) + : allocator(alloc), trackCallees(trackCallees) {} ConstExprEvaluator::~ConstExprEvaluator() {} @@ -1661,14 +1663,10 @@ SymbolicValue ConstExprEvaluator::getUnknown(SILNode *node, getAllocator()); } -/// Analyze the specified values to determine if they are constant values. This -/// is done in code that is not necessarily itself a constexpr function. The +/// Analyze the specified values to determine if they are constant values. This +/// is done in code that is not necessarily itself a constexpr function. The /// results are added to the results list which is a parallel structure to the /// input values. -/// -/// TODO: Return information about which callees were found to be -/// constexprs, which would allow the caller to delete dead calls to them -/// that occur after folding them. void ConstExprEvaluator::computeConstantValues( ArrayRef values, SmallVectorImpl &results) { unsigned numInstEvaluated = 0; @@ -1688,9 +1686,10 @@ void ConstExprEvaluator::computeConstantValues( //===----------------------------------------------------------------------===// ConstExprStepEvaluator::ConstExprStepEvaluator(SymbolicValueAllocator &alloc, - SILFunction *fun) - : evaluator(alloc), internalState(new ConstExprFunctionState( - evaluator, fun, {}, stepsEvaluated)) { + SILFunction *fun, + bool trackCallees) + : evaluator(alloc, trackCallees), internalState(new ConstExprFunctionState( + evaluator, fun, {}, stepsEvaluated)) { assert(fun); } diff --git a/test/SILOptimizer/constant_evaluable_subset_test.swift b/test/SILOptimizer/constant_evaluable_subset_test.swift new file mode 100644 index 0000000000000..bc9923015afe4 --- /dev/null +++ b/test/SILOptimizer/constant_evaluable_subset_test.swift @@ -0,0 +1,695 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-silgen -primary-file %s -o %t/constant_evaluable_subset_test_silgen.sil +// +// Run the (mandatory) passes on which constant evaluator depends, and test the +// constant evaluator on the SIL produced after the dependent passes are run. +// +// RUN: not %target-sil-opt -silgen-cleanup -raw-sil-inst-lowering -allocbox-to-stack -mandatory-inlining -constexpr-limit 3000 -test-constant-evaluable-subset %t/constant_evaluable_subset_test_silgen.sil > /dev/null 2> %t/error-output +// +// RUN: %FileCheck %s < %t/error-output +// +// Test the constant evaluator on the output of the mandatory pipeline. This is +// to test that constant evaluability is not affected by mandatory +// optimizations. Note that it can be affected by non-mandatory optimizations, +// especially performance inlining as it inlines functions such as String.+= +// that the evaluator has special knowledge about. +// +// RUN: not %target-sil-opt -silgen-cleanup -diagnose-invalid-escaping-captures -diagnose-static-exclusivity -capture-promotion -access-enforcement-selection -allocbox-to-stack -noreturn-folding -mark-uninitialized-fixup -definite-init -raw-sil-inst-lowering -closure-lifetime-fixup -semantic-arc-opts -destroy-hoisting -ownership-model-eliminator -mandatory-inlining -predictable-memaccess-opts -os-log-optimization -diagnostic-constant-propagation -predictable-deadalloc-elim -guaranteed-arc-opts -diagnose-unreachable -diagnose-infinite-recursion -yield-once-check -dataflow-diagnostics -split-non-cond_br-critical-edges -constexpr-limit 3000 -test-constant-evaluable-subset %t/constant_evaluable_subset_test_silgen.sil > /dev/null 2> %t/error-output-mandatory +// +// RUN: %FileCheck %s < %t/error-output-mandatory + +// Test Swift code snippets that are expected to be constant evaluable and those +// that are not. If any of the test here fails, it indicates a change in the +// output of SILGen or the mandatory passes that affects the constant +// evaluability of the corresponding Swift code. + +// CHECK-LABEL: @leftShift +// CHECK-NOT: error: +@_semantics("constant_evaluable") +internal func leftShift(x: Int, y: Int) -> Int { + return x &<< y +} + +// The test driver must only call functions marked as constant evaluable +// with literal arguments. +@_semantics("test_driver") +internal func interpretLeftShiftTest() -> Int { + return leftShift(x: 10, y: 2) +} + +// CHECK-LABEL: @leftShiftWithTraps +// CHECK-NOT: error: +// This is an expensive function to evaluate requiring evaluating approximately +// 1024 instructions. +@_semantics("constant_evaluable") +internal func leftShiftWithTraps(x: Int, y: Int) -> Int { + return x << y +} + +@_semantics("test_driver") +internal func interpretLeftShiftWithTraps() -> Int { + return leftShiftWithTraps(x: 34, y: 3) +} + +// CHECK-LABEL: @rightShift +// CHECK-NOT: error: +@_semantics("constant_evaluable") +internal func rightShift(x: Int, y: Int) -> Int { + return x &>> y +} + +@_semantics("test_driver") +internal func interpretRightShift() -> Int { + return rightShift(x: 10, y: 2) +} + +// CHECK-LABEL: @rightShiftWithTraps +// CHECK-NOT: error: +// This is an expensive function to evaluate requiring evaluating approximately +// 1024 instructions. +@_semantics("constant_evaluable") +internal func rightShiftWithTraps(x: Int, y: Int) -> Int { + return x >> y +} + +@_semantics("test_driver") +internal func interpretRightShiftWithTraps() -> Int { + return rightShiftWithTraps(x: 34, y: 3) +} + +// CHECK-LABEL: @arithmetic +// CHECK-NOT: error: +@_semantics("constant_evaluable") +internal func arithmetic(x: Int, y: Int) -> Int { + let z = x + y + let w = x &+ z + let a = w * y + let b = a &* z + let c = b - a + let d = c &- x + let e = x / d + return e +} + +@_semantics("test_driver") +internal func interpretArithmetic() -> Int { + return arithmetic(x: 142, y: 212) +} + +// CHECK-LABEL: @booleanoperations +// CHECK-NOT: error: +@_semantics("constant_evaluable") +internal func booleanoperations(a: Bool, b: Bool) -> Bool { + return (a && b) || (a || b) && !a +} + +@_semantics("test_driver") +internal func interpretBooleanOperations() -> Bool { + return booleanoperations(a: true, b: false) +} + +// CHECK-LABEL: @comparisons +// CHECK-NOT: error: +@_semantics("constant_evaluable") +internal func comparisons(a: Int, b: Int, c: Int8, d: Int8) -> Bool { + let r1 = a < b + let r2 = c > d + return r1 && r2 +} + +@_semantics("test_driver") +internal func interpretComparisions() -> Bool { + return comparisons(a: 20, b: 55, c: 56, d: 101) +} + +// CHECK-LABEL: @heterogenousIntComparisons +// CHECK-NOT: error: +@_semantics("constant_evaluable") +internal func heterogenousIntComparisons(a: Int, b: Int16, c: Int8) -> Bool { + return (a < b) && (c < b) +} + +@_semantics("test_driver") +internal func interpretHeterogenousComparisons() -> Bool { + return heterogenousIntComparisons(a: 101, b: 20, c: 56) +} + +// CHECK-LABEL: @bitwiseOperations +// CHECK-NOT: error: +@_semantics("constant_evaluable") +internal func bitwiseOperations(a: Int16, b: Int16, c: Int16) -> Int16 { + return a & ((b | c) | ~c) +} + +@_semantics("test_driver") +internal func interpretBitWiseOperations() -> Int16 { + return bitwiseOperations(a: 0xff, b: 0xef, c: 0x7fef) +} + +// CHECK-LABEL: @testIntExtensions +// CHECK-NOT: error: +@_semantics("constant_evaluable") +internal func testIntExtensions(a: Int8, b: Int16) -> Int32 { + return Int32(a) + Int32(b) + Int32(Int16(a)) +} + +@_semantics("test_driver") +internal func interpretIntExtensions() -> Int32 { + return testIntExtensions(a: 100, b: -130) +} + +// CHECK-LABEL: @testUIntExtensions +// CHECK-NOT: error: +@_semantics("constant_evaluable") +internal func testUIntExtensions(a: UInt8, b: UInt16) -> UInt32 { + return UInt32(a) + UInt32(b) + UInt32(UInt16(a)) +} + +@_semantics("test_driver") +internal func interpretUIntExtensions() -> UInt32 { + return testUIntExtensions(a: 100, b: 130) +} + +// CHECK-LABEL: @testIntTruncations +// CHECK-NOT: error: +// This is an expensive function to evaluate requiring evaluating approximately +// 2048 instructions with optimized stdlib and 3000 instructions with +// unoptimized stdlib. +@_semantics("constant_evaluable") +internal func testIntTruncations(a: Int32) -> Int8 { + let b = Int16(a) + let c = Int8(b) + return c +} + +@_semantics("test_driver") +internal func interpretIntTruncations() -> Int8 { + return testIntTruncations(a: 100) +} + +// CHECK-LABEL: @testInvalidIntTruncations +// CHECK: error: not constant evaluable +@_semantics("constant_evaluable") +internal func testInvalidIntTruncations(a: Int32) -> Int8 { + return Int8(a) + // CHECK: note: assertion failed with message: Fatal error: Not enough bits to represent the passed value: {{.*}}/Integers.swift: + // CHECK: note: assertion failed during this call + // CHECK: function_ref @$sSZss17FixedWidthIntegerRzrlEyxqd__cSzRd__lufC +} + +@_semantics("test_driver") +internal func interpretInvalidIntTruncations() -> Int8 { + return testInvalidIntTruncations(a: 130) +} + +// CHECK-LABEL: @testUIntTruncations +// CHECK-NOT: error: +// This is an expensive function to evaluate requiring evaluating approximately +// 2048 instructions. +@_semantics("constant_evaluable") +internal func testUIntTruncations(a: UInt32) -> UInt8 { + let b = UInt32(a) + let c = UInt16(b) + let d = UInt8(c) + return d +} + +@_semantics("test_driver") +internal func interpretUIntTruncations() -> UInt8 { + return testUIntTruncations(a: 100) +} + +// CHECK-LABEL: @testSingedUnsignedConversions +// CHECK-NOT: error: +// This is an expensive function to evaluate requiring evaluating approximately +// 2048 instructions. +@_semantics("constant_evaluable") +internal func testSingedUnsignedConversions(a: Int32, b: UInt8) -> UInt32 { + return UInt32(a) + UInt32(Int8(b)) +} + +@_semantics("test_driver") +internal func interpretSingedUnsignedConversions() -> UInt32 { + return testSingedUnsignedConversions(a: 100, b: 120) +} + +// CHECK-LABEL: @testInvalidSingedUnsignedConversions +// CHECK: error: not constant evaluable +@_semantics("constant_evaluable") +internal func testInvalidSingedUnsignedConversions(a: Int64) -> UInt64 { + return UInt64(a) + // CHECK: note: assertion failed with message: Fatal error: Negative value is not representable: {{.*}}/Integers.swift: + // CHECK: note: assertion failed during this call + // CHECK: function_ref @$sSUss17FixedWidthIntegerRzrlEyxqd__cSzRd__lufC +} + +@_semantics("test_driver") +internal func interpretInvalidSingedUnsignedConversions() -> UInt64 { + return testInvalidSingedUnsignedConversions(a: -130) +} + +// CHECK-LABEL: @testIO +// CHECK: error: not constant evaluable +@_semantics("constant_evaluable") +internal func testIO() -> String? { + return readLine() + // CHECK: note: encountered call to 'Swift.readLine(strippingNewline: Swift.Bool) -> Swift.Optional' whose body is not available + // CHECK: note: function whose body is not available +} + +@_semantics("test_driver") +internal func interpretIO() -> String? { + return testIO() +} + +// CHECK-LABEL: @testLoop +// CHECK: error: not constant evaluable +@_semantics("constant_evaluable") +func testLoop() -> Int { + var x = 0 + while x <= 42 { + x += 1 + } + return x + // CHECK: note: control-flow loop found during evaluation + // CHECK: note: found loop here +} + +@_semantics("test_driver") +internal func interpretLoop() -> Int { + return testLoop() +} + +// CHECK-LABEL: @testRecursion +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testRecursion(_ a: Int) -> Int { + return a <= 0 ? 0 : testRecursion(a-1) +} + +@_semantics("test_driver") +internal func interpretRecursion() -> Int { + return testRecursion(10) +} + +// CHECK-LABEL: @testLongRecursion +// CHECK: error: not constant evaluable +@_semantics("constant_evaluable") +func testLongRecursion(_ a: Int) -> Int { + return a == 0 ? 0 : testLongRecursion(a-1) + // CHECK: note: exceeded instruction limit: + // CHECK: note: limit exceeded here +} + +@_semantics("test_driver") +internal func interpretLongRecursion() -> Int { + return testLongRecursion(-100) +} + +// CHECK-LABEL: @testConditional +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testConditional(_ x: Int) -> Int { + if x < 0 { + return 0 + } else { + return x + } +} + +@_semantics("test_driver") +func interpretConditional() -> Int { + testConditional(-1) +} + +// CHECK-LABEL: @testIntAddOverflow +// CHECK: error: not constant evaluable +@_semantics("constant_evaluable") +func testIntAddOverflow(_ x: Int8) -> Int8 { + return x + 1 + // CHECK: note: integer overflow detected + // CHECK: note: operation overflows +} + +@_semantics("test_driver") +func interpretIntAddOverflow() -> Int8 { + return testIntAddOverflow(127) +} + +// CHECK-LABEL: @testDivideByZero +// CHECK: error: not constant evaluable +@_semantics("constant_evaluable") +func testDivideByZero(_ x: Int, _ y: Int) -> Int { + return x / y + // CHECK: note: assertion failed with message: Fatal error: Division by zero: {{.*}}/IntegerTypes.swift: + // CHECK: note: assertion failed here +} + +@_semantics("test_driver") +func interpretDivideByZero() -> Int { + return testDivideByZero(127, 0) +} + +// CHECK-LABEL: @testDivideOverflow +// CHECK: error: not constant evaluable +@_semantics("constant_evaluable") +func testDivideOverflow(_ x: Int8, _ y: Int8) -> Int8 { + return x / y + // CHECK: note: assertion failed with message: Fatal error: Division results in an overflow: {{.*}}/IntegerTypes.swift: + // CHECK: note: assertion failed here +} + +@_semantics("test_driver") +func interpretDivideOverflow() -> Int8 { + return testDivideOverflow(-128, -1) +} + +// CHECK-LABEL: @testInOut +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testInOut(_ x: inout Int) { + x += 1 +} + +@_semantics("test_driver") +func interpretInOut() -> Int { + var x = 10 + testInOut(&x) + return x +} + +struct A { + var x, y: Int + + // CHECK-LABEL: @init(initialValue: Int) -> A + // CHECK-NOT: error: + @_semantics("constant_evaluable") + init(initialValue: Int) { + x = initialValue + y = initialValue + } + + // CHECK-LABEL: @sum + // CHECK-NOT: error: + @_semantics("constant_evaluable") + @_optimize(none) + func sum() -> Int { + return x + y + } + + // CHECK-LABEL: @increment + // CHECK-NOT: error: + @_semantics("constant_evaluable") + @_optimize(none) + mutating func increment(by step: Int) { + x += step + y += step + } +} + +@_semantics("test_driver") +func interpretStructInitAndMethods() -> A { + var a = A(initialValue: 0) + let z = a.sum(); + a.increment(by: z) + return a +} + +struct OuterStruct { + var inner: A + var z: Int + + // CHECK-LABEL: @sumInner + // CHECK-NOT: error: + @_semantics("constant_evaluable") + @_optimize(none) + func sumInner() -> Int { + return inner.sum() + } +} + +@_semantics("test_driver") +func interpretNestedStructAndDefaultInit() -> Int { + let ostruct = OuterStruct(inner: A(initialValue: 1), z: 10) + return ostruct.sumInner() +} + +struct EmptyStruct { + func get() -> Int { + return 0 + } +} + +// CHECK-LABEL: @testEmptyStruct +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testEmptyStruct() -> Int { + let emp = EmptyStruct() + return emp.get() +} + +@_semantics("test_driver") +func interpretEmptyStructTest() -> Int { + return testEmptyStruct() +} + +// CHECK-LABEL: @testTuple +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testTuple(_ a: Int, _ b: Bool) -> Bool { + func extractSecond(_ tuple: (Int, Bool)) -> Bool { + return tuple.1 + } + return extractSecond((a, b)) +} + +@_semantics("test_driver") +func interpretTuple() -> Bool { + return testTuple(10, false) +} + +// CHECK-LABEL: @testGenericFunction +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testGenericFunction(_ a: T, _ b: T) -> Bool { + return a == b +} + +@_semantics("test_driver") +func interpretGenericFunction() -> Bool { + return testGenericFunction(10, 11) +} + +protocol P { + mutating func clear() -> Int +} + +struct PImpl: P { + var i = 100 + mutating func clear() -> Int { + let prev = i + i = 0 + return prev + } +} + +// CHECK-LABEL: @testCustomGenericConstraint +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testCustomGenericConstraint(_ a: inout T) -> Int { + return a.clear() +} + +@_semantics("test_driver") +func interpretCustomGenericConstraint() -> Int { + var s = PImpl(); + return testCustomGenericConstraint(&s) +} + +// CHECK-LABEL: @testProtocolMethodDispatch +// CHECK: error: not constant evaluable +@_semantics("constant_evaluable") +func testProtocolMethodDispatch(_ s: PImpl) -> Int { + func innerFunc(_ proto: P) -> Int { + var tmp = proto + return tmp.clear() + } + return innerFunc(s) + // CHECK: note: encountered operation not supported by the evaluator: init_existential_addr + // CHECK: note: operation not supported by the evaluator +} + +@_semantics("test_driver") +func interpretProtocolMethodDispatch() -> Int { + return testProtocolMethodDispatch(PImpl()) +} + +struct SGeneric { + var x: X + var y: Y + + // CHECK-LABEL: @methodWithGeneric + // CHECK-NOT: error: + @_semantics("constant_evaluable") + @_optimize(none) + func methodWithGeneric(_ z: Z) -> SGeneric { + return SGeneric(x: z, y: y) + } +} + +@_semantics("test_driver") +func interpretStructAndMethodWithGeneric() -> SGeneric { + let s = SGeneric(x: 10, y: true) + return s.methodWithGeneric(240) +} + +protocol ProtoWithInit { + init(_ x: Int) +} + +struct C : ProtoWithInit { + init(_ x: Int) { + } +} + +// CHECK-LABEL: @testGenericConstruction +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testGenericConstruction(_: T.Type) -> T { + return T(0) +} + +@_semantics("test_driver") +func interpretGenericConstruction() -> C { + return testGenericConstruction(C.self) +} + +// CHECK-LABEL: @testSupportedStringOperations +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testSupportedStringOperations(_ x: String, _ y: String) -> Bool { + var z = x + z += y + return z == x +} + +@_semantics("test_driver") +func interpretSupportedStringOperations() -> Bool { + return testSupportedStringOperations("abc", "zyx") +} + +// CHECK-LABEL: @testOptional +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testOptional(_ xopt: String?) -> String { + if let x = xopt { + return x + } + return "" +} + +@_semantics("test_driver") +func interpretOptionalTest() -> String { + return testOptional("a") +} + +enum Side { + case right + case left +} + +// CHECK-LABEL: @testEnumSwitch +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testEnumSwitch(_ side: Side) -> Int { + switch side { + case .right: + return 1 + case .left: + return 0 + } +} + +@_semantics("test_driver") +func interpretEnumSwitch() -> Int { + return testEnumSwitch(.right) +} + +// CHECK-LABEL: @testEnumEquality +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testEnumEquality(_ side: Side, _ otherSide: Side) -> Bool { + return side == otherSide +} + +@_semantics("test_driver") +func interpretEnumEquality() -> Bool { + return testEnumEquality(.right, .left) +} + +enum Shape { + case circle(radius: Int) + case rectangle(length: Int, breadth: Int) +} + +// CHECK-LABEL: @testEnumWithData +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testEnumWithData(_ shape: Shape) -> Int { + switch shape { + case .circle(radius: let x): + return x + case .rectangle(length: let x, breadth: let y): + return x + y + } +} + +@_semantics("test_driver") +func interpretEnumWithData() -> Int { + return testEnumWithData(.circle(radius: 11)) +} + +enum Number { + case integer(T) + case rational(T, T) +} + +// CHECK-LABEL: @testAddressOnlyEnum +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testAddressOnlyEnum(_ number: Number) -> T { + switch number { + case .integer(let x): + return x + case .rational(let x, let y): + return x + y + } +} + +@_semantics("test_driver") +func interpretAddressOnlyEnum() -> Int { + return testAddressOnlyEnum(.rational(22, 7)) +} + +indirect enum Nat { + case zero + case succ(Nat) +} + +// CHECK-LABEL: @testIndirectEnum +// CHECK: error: not constant evaluable +@_semantics("constant_evaluable") +func testIndirectEnum(_ nat: Nat) -> Bool { + switch nat { + case .zero: + return true + case .succ: + return false + } + // CHECK-NOTE: note: encountered operation not supported by the evaluator: alloc_box +} + +@_semantics("test_driver") +func interpretIndirectEnum() -> Bool { + return testIndirectEnum(.succ(.zero)) +} diff --git a/test/SILOptimizer/constant_evaluable_subset_test_arch32.swift b/test/SILOptimizer/constant_evaluable_subset_test_arch32.swift new file mode 100644 index 0000000000000..cd8ab82a59aaa --- /dev/null +++ b/test/SILOptimizer/constant_evaluable_subset_test_arch32.swift @@ -0,0 +1,102 @@ +// REQUIRES: PTRSIZE=32 +// +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-silgen -primary-file %s -o %t/constant_evaluable_subset_test_arch32_silgen.sil +// +// Run the (mandatory) passes on which constant evaluator depends, and test the +// constant evaluator on the SIL produced after the dependent passes are run. +// +// RUN: not %target-sil-opt -silgen-cleanup -raw-sil-inst-lowering -allocbox-to-stack -mandatory-inlining -constexpr-limit 3000 -test-constant-evaluable-subset %t/constant_evaluable_subset_test_arch32_silgen.sil > /dev/null 2> %t/error-output +// +// RUN: %FileCheck %s < %t/error-output + +// Test Swift code snippets that are expected to be constant evaluable and those +// that are not. If any of the test here fails, it indicates a change in the +// output of SILGen or the mandatory passes that affects the constant +// evaluability of the corresponding Swift code. The tests here are specific +// to 32bit architecture. + +// Unfortunately, on 32bit architectures the following operations are not +// constant evaluable, as it requires supporting co-routines in the evaluator. +// They are however constant evaluable on 64bit architectures. This difference +// arises because in 32bit architecture Int64 occupies multiple words and +// the following operations involves iterating through the words in Int64. This +// causes the interpreted code to change between 64bit and 32bit architectures. + +// CHECK-LABEL: @testIntExtensions +// CHECK: error: not constant evaluable +// CHECK: note: encountered operation not supported by the evaluator: begin_apply +@_semantics("constant_evaluable") +internal func testIntExtensions(a: Int8, b: Int16, c: Int32) -> Int64 { + return Int64(a) + Int64(b) + Int64(c) +} + +@_semantics("test_driver") +internal func interpretIntExtensions() -> Int64 { + return testIntExtensions(a: 100, b: -130, c: -50000) +} + +// CHECK-LABEL: @testUIntExtensions +// CHECK: error: not constant evaluable +// CHECK: note: encountered operation not supported by the evaluator: begin_apply +@_semantics("constant_evaluable") +internal func testUIntExtensions(a: UInt8, b: UInt16, c: UInt32) -> UInt64 { + return UInt64(a) + UInt64(b) + UInt64(c) +} + +@_semantics("test_driver") +internal func interpretUIntExtensions() -> UInt64 { + return testUIntExtensions(a: 100, b: 130, c: 0xffffffff) +} + +// CHECK-LABEL: @testIntTruncations +// CHECK: error: not constant evaluable +// CHECK: note: encountered operation not supported by the evaluator: begin_apply +@_semantics("constant_evaluable") +internal func testIntTruncations(a: Int64) -> Int16 { + return Int16(a) +} + +@_semantics("test_driver") +internal func interpretIntTruncations() -> Int16 { + return testIntTruncations(a: 100) +} + +// CHECK-LABEL: @testInvalidIntTruncations +// CHECK: error: not constant evaluable +// CHECK: note: encountered operation not supported by the evaluator: begin_apply +@_semantics("constant_evaluable") +internal func testInvalidIntTruncations(a: Int64) -> Int8 { + return Int8(a) +} + +@_semantics("test_driver") +internal func interpretInvalidIntTruncations() -> Int8 { + return testInvalidIntTruncations(a: 130) +} + +// CHECK-LABEL: @testUIntTruncations +// CHECK: error: not constant evaluable +// CHECK: note: encountered operation not supported by the evaluator: begin_apply +@_semantics("constant_evaluable") +internal func testUIntTruncations(a: UInt64) -> UInt16 { + return UInt16(a) +} + +@_semantics("test_driver") +internal func interpretUIntTruncations() -> UInt16 { + return testUIntTruncations(a: 100) +} + +// CHECK-LABEL: @testSingedUnsignedConversions +// CHECK: error: not constant evaluable +// CHECK: note: encountered operation not supported by the evaluator: begin_apply +@_semantics("constant_evaluable") +internal func testSingedUnsignedConversions(a: Int64, b: UInt8) -> UInt64 { + return UInt64(a) + UInt64(Int8(b)) +} + +@_semantics("test_driver") +internal func interpretSingedUnsignedConversions() -> UInt64 { + return testSingedUnsignedConversions(a: 100, b: 120) +} diff --git a/test/SILOptimizer/constant_evaluable_subset_test_arch64.swift b/test/SILOptimizer/constant_evaluable_subset_test_arch64.swift new file mode 100644 index 0000000000000..449a87e9d3302 --- /dev/null +++ b/test/SILOptimizer/constant_evaluable_subset_test_arch64.swift @@ -0,0 +1,109 @@ +// REQUIRES: PTRSIZE=64 +// +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-silgen -primary-file %s -o %t/constant_evaluable_subset_test_arch64_silgen.sil +// +// Run the (mandatory) passes on which constant evaluator depends, and test the +// constant evaluator on the SIL produced after the dependent passes are run. +// +// RUN: not %target-sil-opt -silgen-cleanup -raw-sil-inst-lowering -allocbox-to-stack -mandatory-inlining -constexpr-limit 3000 -test-constant-evaluable-subset %t/constant_evaluable_subset_test_arch64_silgen.sil > /dev/null 2> %t/error-output +// +// RUN: %FileCheck %s < %t/error-output +// +// Test the constant evaluator on the output of the mandatory pipeline. This is +// to test that constant evaluability is not affected by mandatory +// optimizations. Note that it can be affected by non-mandatory optimizations, +// especially performance inlining as it inlines functions such as String.+= +// that the evaluator has special knowledge about. +// +// RUN: not %target-sil-opt -silgen-cleanup -diagnose-invalid-escaping-captures -diagnose-static-exclusivity -capture-promotion -access-enforcement-selection -allocbox-to-stack -noreturn-folding -mark-uninitialized-fixup -definite-init -raw-sil-inst-lowering -closure-lifetime-fixup -semantic-arc-opts -destroy-hoisting -ownership-model-eliminator -mandatory-inlining -predictable-memaccess-opts -os-log-optimization -diagnostic-constant-propagation -predictable-deadalloc-elim -guaranteed-arc-opts -diagnose-unreachable -diagnose-infinite-recursion -yield-once-check -dataflow-diagnostics -split-non-cond_br-critical-edges -constexpr-limit 3000 -test-constant-evaluable-subset %t/constant_evaluable_subset_test_arch64_silgen.sil > /dev/null 2> %t/error-output-mandatory +// +// RUN: %FileCheck %s < %t/error-output-mandatory + +// Test Swift code snippets that are expected to be constant evaluable and those +// that are not. If any of the test here fails, it indicates a change in the +// output of SILGen or the mandatory passes that affects the constant +// evaluability of the corresponding Swift code. The tests here are specific +// to 64bit architecture. + +// CHECK-LABEL: @testIntExtensions +// CHECK-NOT: error: +@_semantics("constant_evaluable") +internal func testIntExtensions(a: Int8, b: Int16, c: Int32) -> Int64 { + return Int64(a) + Int64(b) + Int64(c) +} + +@_semantics("test_driver") +internal func interpretIntExtensions() -> Int64 { + return testIntExtensions(a: 100, b: -130, c: -50000) +} + +// CHECK-LABEL: @testUIntExtensions +// CHECK-NOT: error: +@_semantics("constant_evaluable") +internal func testUIntExtensions(a: UInt8, b: UInt16, c: UInt32) -> UInt64 { + return UInt64(a) + UInt64(b) + UInt64(c) +} + +@_semantics("test_driver") +internal func interpretUIntExtensions() -> UInt64 { + return testUIntExtensions(a: 100, b: 130, c: 0xffffffff) +} + +// CHECK-LABEL: @testIntTruncations +// CHECK-NOT: error: +// This is an expensive function to evaluate requiring evaluating approximately +// 2048 instructions with optimized stdlib and 3000 instructions with +// unoptimized stdlib. +@_semantics("constant_evaluable") +internal func testIntTruncations(a: Int64) -> Int16 { + return Int16(a) +} + +@_semantics("test_driver") +internal func interpretIntTruncations() -> Int16 { + return testIntTruncations(a: 100) +} + +// CHECK-LABEL: @testInvalidIntTruncations +// CHECK: error: not constant evaluable +@_semantics("constant_evaluable") +internal func testInvalidIntTruncations(a: Int64) -> Int8 { + return Int8(a) + // CHECK: note: assertion failed with message: Fatal error: Not enough bits to represent the passed value: {{.*}}/Integers.swift: + // CHECK: note: assertion failed during this call + // CHECK: function_ref @$sSZss17FixedWidthIntegerRzrlEyxqd__cSzRd__lufC +} + +@_semantics("test_driver") +internal func interpretInvalidIntTruncations() -> Int8 { + return testInvalidIntTruncations(a: 130) +} + +// CHECK-LABEL: @testUIntTruncations +// CHECK-NOT: error: +// This is an expensive function to evaluate requiring evaluating approximately +// 2048 instructions. +@_semantics("constant_evaluable") +internal func testUIntTruncations(a: UInt64) -> UInt16 { + return UInt16(a) +} + +@_semantics("test_driver") +internal func interpretUIntTruncations() -> UInt16 { + return testUIntTruncations(a: 100) +} + +// CHECK-LABEL: @testSingedUnsignedConversions +// CHECK-NOT: error: +// This is an expensive function to evaluate requiring evaluating approximately +// 2048 instructions. +@_semantics("constant_evaluable") +internal func testSingedUnsignedConversions(a: Int64, b: UInt8) -> UInt64 { + return UInt64(a) + UInt64(Int8(b)) +} + +@_semantics("test_driver") +internal func interpretSingedUnsignedConversions() -> UInt64 { + return testSingedUnsignedConversions(a: 100, b: 120) +} From dceca2bc3b4d9431598c51e2804dfb5f049143c0 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Mon, 16 Sep 2019 19:38:41 -0700 Subject: [PATCH 039/199] [ownership] Create a context structure for the linear lifetime checker. This is just a simple refactoring commit in preparation for hiding more of the details of the linear lifetime checker. This is NFC, just moving around code. --- include/swift/SIL/OwnershipUtils.h | 61 +++++++++++++------ lib/SIL/LinearLifetimeChecker.cpp | 9 ++- lib/SIL/OwnershipUtils.cpp | 6 +- lib/SIL/SILOwnershipVerifier.cpp | 6 +- .../Mandatory/MandatoryInlining.cpp | 18 +++--- .../Mandatory/PredictableMemOpt.cpp | 5 +- .../Mandatory/SemanticARCOpts.cpp | 9 ++- 7 files changed, 67 insertions(+), 47 deletions(-) diff --git a/include/swift/SIL/OwnershipUtils.h b/include/swift/SIL/OwnershipUtils.h index 55a8fcb8e5e2f..bbe7737ab0260 100644 --- a/include/swift/SIL/OwnershipUtils.h +++ b/include/swift/SIL/OwnershipUtils.h @@ -127,27 +127,50 @@ class LinearLifetimeError { } }; -/// Returns true if: +/// A class used to validate linear lifetime with respect to an SSA-like +/// definition. /// -/// 1. No consuming uses are reachable from any other consuming use, from any -/// non-consuming uses, or from the producer instruction. -/// 2. The consuming use set jointly post dominates producers and all non -/// consuming uses. +/// This class is able to both validate that a linear lifetime has been properly +/// constructed (for verification and safety purposes) as well as return to the +/// caller upon failure, what the failure was. In certain cases (for instance if +/// there exists a path without a non-consuming use), the class will report back +/// the specific insertion points needed to insert these compensating releases. /// -/// \p value The value whose lifetime we are checking. -/// \p consumingUses the array of users that destroy or consume a value. -/// \p nonConsumingUses regular uses -/// \p deadEndBlocks a cache for the dead end block computation -/// \p errorBehavior If we detect an error, should we return false or hard -/// error. -/// \p leakingBlocks If non-null a list of blocks where the value was detected -/// to leak. Can be used to insert missing destroys. -LinearLifetimeError valueHasLinearLifetime( - SILValue value, ArrayRef consumingUses, - ArrayRef nonConsumingUses, - SmallPtrSetImpl &visitedBlocks, - DeadEndBlocks &deadEndBlocks, ownership::ErrorBehaviorKind errorBehavior, - SmallVectorImpl *leakingBlocks = nullptr); +/// DISCUSSION: A linear lifetime consists of a starting block or instruction +/// and a list of non-consuming uses and a set of consuming uses. The consuming +/// uses must not be reachable from each other and jointly post-dominate all +/// consuming uses as well as the defining block/instruction. +class LinearLifetimeChecker { + SmallPtrSetImpl &visitedBlocks; + DeadEndBlocks &deadEndBlocks; + +public: + LinearLifetimeChecker(SmallPtrSetImpl &visitedBlocks, + DeadEndBlocks &deadEndBlocks) + : visitedBlocks(visitedBlocks), deadEndBlocks(deadEndBlocks) {} + + /// Returns true if: + /// + /// 1. No consuming uses are reachable from any other consuming use, from any + /// non-consuming uses, or from the producer instruction. + /// 2. The consuming use set jointly post dominates producers and all non + /// consuming uses. + /// + /// Returns false otherwise. + /// + /// \p value The value whose lifetime we are checking. + /// \p consumingUses the array of users that destroy or consume a value. + /// \p nonConsumingUses regular uses + /// \p errorBehavior If we detect an error, should we return false or hard + /// error. + /// \p leakingBlocks If non-null a list of blocks where the value was detected + /// to leak. Can be used to insert missing destroys. + LinearLifetimeError + checkValue(SILValue value, ArrayRef consumingUses, + ArrayRef nonConsumingUses, + ownership::ErrorBehaviorKind errorBehavior, + SmallVectorImpl *leakingBlocks = nullptr); +}; /// Returns true if v is an address or trivial. bool isValueAddressOrTrivial(SILValue v); diff --git a/lib/SIL/LinearLifetimeChecker.cpp b/lib/SIL/LinearLifetimeChecker.cpp index 5b8eeeaff8073..1697965957cc3 100644 --- a/lib/SIL/LinearLifetimeChecker.cpp +++ b/lib/SIL/LinearLifetimeChecker.cpp @@ -507,10 +507,9 @@ void State::checkDataflowEndState(DeadEndBlocks &deBlocks) { // Top Level Entrypoints //===----------------------------------------------------------------------===// -LinearLifetimeError swift::valueHasLinearLifetime( +LinearLifetimeError LinearLifetimeChecker::checkValue( SILValue value, ArrayRef consumingUses, ArrayRef nonConsumingUses, - SmallPtrSetImpl &visitedBlocks, DeadEndBlocks &deBlocks, ErrorBehaviorKind errorBehavior, SmallVectorImpl *leakingBlocks) { assert(!consumingUses.empty() && "Must have at least one consuming user?!"); @@ -547,7 +546,7 @@ LinearLifetimeError swift::valueHasLinearLifetime( // same block, we would have flagged. if (llvm::any_of(nonConsumingUses, [&](BranchPropagatedUser user) { return user.getParent() != value->getParentBlock() && - !deBlocks.isDeadEnd(user.getParent()); + !deadEndBlocks.isDeadEnd(user.getParent()); })) { state.error.handleUseAfterFree([&] { llvm::errs() << "Function: '" << value->getFunction()->getName() @@ -592,10 +591,10 @@ LinearLifetimeError swift::valueHasLinearLifetime( // Now that our algorithm is completely prepared, run the // dataflow... If we find a failure, return false. - state.performDataflow(deBlocks); + state.performDataflow(deadEndBlocks); // ...and then check that the end state shows that we have a valid linear // typed value. - state.checkDataflowEndState(deBlocks); + state.checkDataflowEndState(deadEndBlocks); return state.error; } diff --git a/lib/SIL/OwnershipUtils.cpp b/lib/SIL/OwnershipUtils.cpp index 3ba913bf3c28f..1d45c332fa032 100644 --- a/lib/SIL/OwnershipUtils.cpp +++ b/lib/SIL/OwnershipUtils.cpp @@ -206,8 +206,8 @@ bool BorrowScopeIntroducingValue::areInstructionsWithinScope( visitLocalScopeEndingInstructions( [&scratchSpace](SILInstruction *i) { scratchSpace.emplace_back(i); }); - auto result = valueHasLinearLifetime( - value, scratchSpace, instructions, visitedBlocks, deadEndBlocks, - ownership::ErrorBehaviorKind::ReturnFalse); + LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks); + auto result = checker.checkValue(value, scratchSpace, instructions, + ownership::ErrorBehaviorKind::ReturnFalse); return !result.getFoundError(); } diff --git a/lib/SIL/SILOwnershipVerifier.cpp b/lib/SIL/SILOwnershipVerifier.cpp index 258c884610df8..5e0f629536bfb 100644 --- a/lib/SIL/SILOwnershipVerifier.cpp +++ b/lib/SIL/SILOwnershipVerifier.cpp @@ -136,9 +136,9 @@ class SILValueOwnershipChecker { SmallVector allRegularUsers; llvm::copy(regularUsers, std::back_inserter(allRegularUsers)); llvm::copy(implicitRegularUsers, std::back_inserter(allRegularUsers)); - auto linearLifetimeResult = - valueHasLinearLifetime(value, lifetimeEndingUsers, allRegularUsers, - visitedBlocks, deadEndBlocks, errorBehavior); + LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks); + auto linearLifetimeResult = checker.checkValue( + value, lifetimeEndingUsers, allRegularUsers, errorBehavior); result = !linearLifetimeResult.getFoundError(); return result.getValue(); diff --git a/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp b/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp index de9993b97515a..82ca1513961cc 100644 --- a/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp +++ b/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp @@ -150,9 +150,9 @@ static void fixupReferenceCounts( // just cares about the block the value is in. In a forthcoming commit, I // am going to change this to use a different API on the linear lifetime // checker that makes this clearer. - auto error = - valueHasLinearLifetime(pai, {applySite}, {}, visitedBlocks, - deadEndBlocks, errorBehavior, &leakingBlocks); + LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks); + auto error = checker.checkValue(pai, {applySite}, {}, errorBehavior, + &leakingBlocks); if (error.getFoundLeak()) { while (!leakingBlocks.empty()) { auto *leakingBlock = leakingBlocks.pop_back_val(); @@ -201,9 +201,9 @@ static void fixupReferenceCounts( // just cares about the block the value is in. In a forthcoming commit, I // am going to change this to use a different API on the linear lifetime // checker that makes this clearer. - auto error = - valueHasLinearLifetime(pai, {applySite}, {}, visitedBlocks, - deadEndBlocks, errorBehavior, &leakingBlocks); + LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks); + auto error = checker.checkValue(pai, {applySite}, {}, errorBehavior, + &leakingBlocks); if (error.getFoundError()) { while (!leakingBlocks.empty()) { auto *leakingBlock = leakingBlocks.pop_back_val(); @@ -240,9 +240,9 @@ static void fixupReferenceCounts( // just cares about the block the value is in. In a forthcoming commit, I // am going to change this to use a different API on the linear lifetime // checker that makes this clearer. - auto error = - valueHasLinearLifetime(pai, {applySite}, {}, visitedBlocks, - deadEndBlocks, errorBehavior, &leakingBlocks); + LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks); + auto error = checker.checkValue(pai, {applySite}, {}, errorBehavior, + &leakingBlocks); if (error.getFoundError()) { while (!leakingBlocks.empty()) { auto *leakingBlock = leakingBlocks.pop_back_val(); diff --git a/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp b/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp index 1d0198392af22..bdc5911faf036 100644 --- a/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp +++ b/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp @@ -780,9 +780,8 @@ AvailableValueAggregator::addMissingDestroysForCopiedValues( // Then perform the linear lifetime check. If we succeed, continue. We have // no further work to do. auto errorKind = ownership::ErrorBehaviorKind::ReturnFalse; - auto error = - valueHasLinearLifetime(cvi, {svi}, {}, visitedBlocks, deadEndBlocks, - errorKind, &leakingBlocks); + LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks); + auto error = checker.checkValue(cvi, {svi}, {}, errorKind, &leakingBlocks); if (!error.getFoundError()) continue; diff --git a/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp b/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp index 7de95d5579d04..f606369010107 100644 --- a/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp +++ b/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp @@ -671,11 +671,10 @@ class StorageGuaranteesLoadVisitor } SmallPtrSet visitedBlocks; - - auto result = valueHasLinearLifetime(baseObject, baseEndBorrows, - valueDestroys, visitedBlocks, - ARCOpt.getDeadEndBlocks(), - ownership::ErrorBehaviorKind::ReturnFalse); + + LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks()); + auto result = checker.checkValue(baseObject, baseEndBorrows, valueDestroys, + ownership::ErrorBehaviorKind::ReturnFalse); return answer(result.getFoundError()); } From c968c14a246d6ff8258e81f17e11d2fb78924e51 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 17 Sep 2019 00:27:12 -0700 Subject: [PATCH 040/199] [Diagnostics] Cover single explicit tuple argument -> N parameters via missing arguments fix Expand tuple into N arguments to cover expect parameters. This covers cases like this: ```swift func foo(_: (Int, Int) -> Void) {} foo { (bar: (Int, Int)) in } // used a single tuple type `(Int, Int)` // instead of two distinct arguments ``` --- lib/Sema/CSDiag.cpp | 6 ++---- lib/Sema/CSSimplify.cpp | 28 +++++++++++++++++++--------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp index 737ec7beabeb9..c5a712de8bdd1 100644 --- a/lib/Sema/CSDiag.cpp +++ b/lib/Sema/CSDiag.cpp @@ -4091,10 +4091,8 @@ bool FailureDiagnosis::diagnoseClosureExpr( return true; } - MissingArgumentsFailure failure( - expr, CS, inferredArgCount - actualArgCount, - CS.getConstraintLocator(CE, LocatorPathElt::ContextualType())); - return failure.diagnoseAsError(); + // Missing arguments are already diagnosed via new diagnostic framework. + return false; } // Coerce parameter types here only if there are no unresolved diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index d21eece744462..28c61599d823c 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -1179,16 +1179,26 @@ static bool fixMissingArguments(ConstraintSystem &cs, Expr *anchor, // tuple e.g. `$0.0`. Optional argumentTuple; if (isa(anchor) && isSingleTupleParam(ctx, args)) { - auto isParam = [](const Expr *expr) { - if (auto *DRE = dyn_cast(expr)) { - if (auto *decl = DRE->getDecl()) - return isa(decl); + auto argType = args.back().getPlainType(); + // Let's unpack argument tuple into N arguments, this corresponds + // to something like `foo { (bar: (Int, Int)) in }` where `foo` + // has a single parameter of type `(Int, Int) -> Void`. + if (auto *tuple = argType->getAs()) { + args.pop_back(); + for (const auto &elt : tuple->getElements()) { + args.push_back(AnyFunctionType::Param(elt.getType(), elt.getName(), + elt.getParameterFlags())); } - return false; - }; + } else if (auto *typeVar = argType->getAs()) { + auto isParam = [](const Expr *expr) { + if (auto *DRE = dyn_cast(expr)) { + if (auto *decl = DRE->getDecl()) + return isa(decl); + } + return false; + }; - const auto &arg = args.back(); - if (auto *argTy = arg.getPlainType()->getAs()) { + // Something like `foo { x in }` or `foo { $0 }` anchor->forEachChildExpr([&](Expr *expr) -> Expr * { if (auto *UDE = dyn_cast(expr)) { if (!isParam(UDE->getBase())) @@ -1200,7 +1210,7 @@ static bool fixMissingArguments(ConstraintSystem &cs, Expr *anchor, llvm::any_of(params, [&](const AnyFunctionType::Param ¶m) { return param.getLabel() == name; })) { - argumentTuple.emplace(argTy); + argumentTuple.emplace(typeVar); args.pop_back(); return nullptr; } From 2ab5ea892694a24c99de92f424d63cc2ba81d3eb Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 13 Sep 2019 11:03:22 -0700 Subject: [PATCH 041/199] Define UnderlyingTypeRequest Define a request for computing the interface type of the underlying type of a typealias. This can be used in place of the declared interface type of the alias itself when it is nested to preserve the fragile validation ordering issues that can cause. --- include/swift/AST/Decl.h | 2 ++ include/swift/AST/TypeCheckRequests.h | 22 +++++++++++++++++++++ include/swift/AST/TypeCheckerTypeIDZone.def | 2 ++ lib/AST/TypeCheckRequests.cpp | 21 ++++++++++++++++++++ 4 files changed, 47 insertions(+) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 38e336135ebaf..81c27aa11d9f4 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -2947,6 +2947,8 @@ class OpaqueTypeDecl : public GenericTypeDecl { /// TypeAliasDecl's always have 'MetatypeType' type. /// class TypeAliasDecl : public GenericTypeDecl { + friend class UnderlyingTypeRequest; + /// The location of the 'typealias' keyword SourceLoc TypeAliasLoc; diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index cf562bd6feb32..2917508499a62 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -1181,6 +1181,28 @@ class GenericSignatureRequest : void cacheResult(GenericSignature *value) const; }; +/// Compute the interface type of the underlying definition type of a typealias declaration. +class UnderlyingTypeRequest : + public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + llvm::Expected evaluate(Evaluator &evaluator, + TypeAliasDecl *decl) const; + +public: + // Caching. + bool isCached() const { return true; } + Optional getCachedResult() const; + void cacheResult(Type value) const; +}; + // Allow AnyValue to compare two Type values, even though Type doesn't // support ==. template<> diff --git a/include/swift/AST/TypeCheckerTypeIDZone.def b/include/swift/AST/TypeCheckerTypeIDZone.def index 7d14fbbfd941c..366f11d775700 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -132,5 +132,7 @@ SWIFT_REQUEST(TypeChecker, SynthesizeAccessorRequest, SeparatelyCached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, TypeCheckFunctionBodyUntilRequest, bool(AbstractFunctionDecl *, SourceLoc), Cached, NoLocationInfo) +SWIFT_REQUEST(TypeChecker, UnderlyingTypeRequest, Type(TypeAliasDecl *), + SeparatelyCached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, USRGenerationRequest, std::string(const ValueDecl *), Cached, NoLocationInfo) diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index f3814ce7d0b91..94aab51ab3ced 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -822,3 +822,24 @@ void GenericSignatureRequest::cacheResult(GenericSignature *value) const { auto *GC = std::get<0>(getStorage()); GC->GenericSigAndBit.setPointerAndInt(value, true); } + +//----------------------------------------------------------------------------// +// IsImplicitlyUnwrappedOptionalRequest computation. +//----------------------------------------------------------------------------// + +Optional +UnderlyingTypeRequest::getCachedResult() const { + auto *typeAlias = std::get<0>(getStorage()); + if (auto type = typeAlias->UnderlyingTy.getType()) + return type; + return None; +} + +void UnderlyingTypeRequest::cacheResult(Type value) const { + auto *typeAlias = std::get<0>(getStorage()); + // lldb creates global typealiases containing archetypes + // sometimes... + if (value->hasArchetype() && typeAlias->isGenericContext()) + value = value->mapTypeOutOfContext(); + typeAlias->UnderlyingTy.setType(value); +} From 278ead39d0e1e72ec796fcea6707e458ce8934da Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 13 Sep 2019 11:08:32 -0700 Subject: [PATCH 042/199] Resugar the structural type Structural type computation ought to actually return a typealias type here using the same mechanism we compute the interface type with (minus the metatype). --- lib/Sema/TypeCheckGeneric.cpp | 45 ++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index e58655319b6a5..8c62dc6e985c7 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -965,15 +965,44 @@ RequirementRequest::evaluate(Evaluator &evaluator, } llvm::Expected -swift::StructuralTypeRequest::evaluate(Evaluator &evaluator, - TypeAliasDecl *D) const { - TypeResolutionOptions options(TypeResolverContext::TypeAliasDecl); - if (!D->getDeclContext()->isCascadingContextForLookup( - /*functionsAreNonCascading*/true)) { +StructuralTypeRequest::evaluate(Evaluator &evaluator, + TypeAliasDecl *typeAlias) const { + // Fast path: If the interface type is already resolved, there's no need + // to compute the structural type. This also prevents us from writing + // ErrorTypes into otherwise valid ASTs with generated typealiases. + if (typeAlias->hasInterfaceType()) { + return typeAlias->getInterfaceType()->getMetatypeInstanceType(); + } + + TypeResolutionOptions options((typeAlias->getGenericParams() + ? TypeResolverContext::GenericTypeAliasDecl + : TypeResolverContext::TypeAliasDecl)); + + if (!typeAlias->getDeclContext()->isCascadingContextForLookup( + /*functionsAreNonCascading*/ true)) { options |= TypeResolutionFlags::KnownNonCascadingDependency; } + + // This can happen when code completion is attempted inside + // of typealias underlying type e.g. `typealias F = () -> Int#^TOK^#` + auto &ctx = typeAlias->getASTContext(); + auto underlyingTypeRepr = typeAlias->getUnderlyingTypeRepr(); + if (!underlyingTypeRepr) { + typeAlias->setInvalid(); + return ErrorType::get(ctx); + } - auto typeRepr = D->getUnderlyingTypeLoc().getTypeRepr(); - auto resolution = TypeResolution::forStructural(D); - return resolution.resolveType(typeRepr, options); + auto resolution = TypeResolution::forStructural(typeAlias); + auto type = resolution.resolveType(underlyingTypeRepr, options); + + auto *genericSig = typeAlias->getGenericSignature(); + SubstitutionMap subs; + if (genericSig) + subs = genericSig->getIdentitySubstitutionMap(); + + Type parent; + auto parentDC = typeAlias->getDeclContext(); + if (parentDC->isTypeContext()) + parent = parentDC->getDeclaredInterfaceType(); + return TypeAliasType::get(typeAlias, parent, subs, type); } From dceb357256cd3e89512a20e8c7ab3509581534a1 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 13 Sep 2019 11:10:28 -0700 Subject: [PATCH 043/199] Improve the TypeAlias{Type|Decl} dump Dump the underlying type by desugaring ourselves a little. --- lib/AST/ASTDumper.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 62c8cec253ef9..5564d8f1984a3 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -616,9 +616,9 @@ namespace { void visitTypeAliasDecl(TypeAliasDecl *TAD) { printCommon(TAD, "typealias"); PrintWithColorRAII(OS, TypeColor) << " type='"; - if (TAD->getUnderlyingTypeLoc().getType()) { + if (auto underlying = TAD->getUnderlyingType()) { PrintWithColorRAII(OS, TypeColor) - << TAD->getUnderlyingTypeLoc().getType().getString(); + << underlying.getString(); } else { PrintWithColorRAII(OS, TypeColor) << "<<>>"; } @@ -3378,6 +3378,12 @@ namespace { void visitTypeAliasType(TypeAliasType *T, StringRef label) { printCommon(label, "type_alias_type"); printField("decl", T->getDecl()->printRef()); + PrintWithColorRAII(OS, TypeColor) << " underlying='"; + if (auto underlying = T->getSinglyDesugaredType()) { + PrintWithColorRAII(OS, TypeColor) << underlying->getString(); + } else { + PrintWithColorRAII(OS, TypeColor) << "<<>>"; + } if (T->getParent()) printRec("parent", T->getParent()); From 5e34169acac91f988582c6367cf66b75eb572905 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 13 Sep 2019 11:13:03 -0700 Subject: [PATCH 044/199] Separate computing interface types and underlying types Computing the interface type of a typealias used to push validation forward and recompute the interface type on the fly. This was fragile and inconsistent with the way interface types are computed in the rest of the decls. Separate these two notions, and plumb through explicit interface type computations with the same "computeType" idiom. This will better allow us to identify the places where we have to force an interface type computation. Also remove access to the underlying type loc. It's now just a cache location the underlying type request will use. Push a type repr accessor to the places that need it, and push the underlying type accessor for everywhere else. Getting the structural type is still preferred for pre-validated computations. This required the resetting of a number of places where we were - in many cases tacitly - asking the question "does the interface type exist". This enables the removal of validateDeclForNameLookup --- include/swift/AST/Decl.h | 18 ++- lib/AST/ASTPrinter.cpp | 4 +- lib/AST/ASTWalker.cpp | 5 +- lib/AST/Decl.cpp | 61 ++++--- lib/AST/DiagnosticEngine.cpp | 2 +- lib/AST/GenericSignatureBuilder.cpp | 10 +- lib/AST/Module.cpp | 2 + lib/AST/NameLookup.cpp | 13 +- lib/ClangImporter/ClangImporter.cpp | 2 +- lib/ClangImporter/ImportDecl.cpp | 23 ++- lib/IDE/CodeCompletion.cpp | 2 +- lib/IRGen/IRGenDebugInfo.cpp | 2 + lib/Index/Index.cpp | 2 +- lib/Parse/ParseDecl.cpp | 2 +- lib/Sema/CSApply.cpp | 2 +- lib/Sema/CalleeCandidateInfo.cpp | 2 +- lib/Sema/NameBinding.cpp | 2 +- lib/Sema/TypeCheckAccess.cpp | 9 +- lib/Sema/TypeCheckDecl.cpp | 221 +++++++++++++++++++++++--- lib/Sema/TypeCheckProtocol.cpp | 4 +- lib/Sema/TypeCheckType.cpp | 111 +++++++------ lib/Serialization/Deserialization.cpp | 24 ++- lib/Serialization/Serialization.cpp | 4 +- 23 files changed, 385 insertions(+), 142 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 81c27aa11d9f4..5b96cc7c7e049 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -2976,20 +2976,28 @@ class TypeAliasDecl : public GenericTypeDecl { void setTypeEndLoc(SourceLoc e) { TypeEndLoc = e; } - TypeLoc &getUnderlyingTypeLoc() { - return UnderlyingTy; + /// Retrieve the TypeRepr corresponding to the parsed underlying type. + TypeRepr *getUnderlyingTypeRepr() const { + return UnderlyingTy.getTypeRepr(); } - const TypeLoc &getUnderlyingTypeLoc() const { - return UnderlyingTy; + void setUnderlyingTypeRepr(TypeRepr *repr) { + UnderlyingTy = repr; } - + + /// Retrieve the interface type of the underlying type. + Type getUnderlyingType() const; void setUnderlyingType(Type type); /// For generic typealiases, return the unbound generic type. UnboundGenericType *getUnboundGenericType() const; + /// Retrieve a sugared interface type containing the structure of the interface + /// type before any semantic validation has occured. Type getStructuralType() const; + /// Set the interface type of this typealias declaration from the underlying type. + void computeType(); + bool isCompatibilityAlias() const { return Bits.TypeAliasDecl.IsCompatibilityAlias; } diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 93655487e66c5..29d9e2cbcc7c2 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -2276,7 +2276,7 @@ void PrintAST::visitTypeAliasDecl(TypeAliasDecl *decl) { printGenericDeclGenericParams(decl); }); bool ShouldPrint = true; - Type Ty = decl->getUnderlyingTypeLoc().getType(); + Type Ty = decl->getUnderlyingType(); // If the underlying type is private, don't print it. if (Options.SkipPrivateStdlibDecls && Ty && Ty.isPrivateStdlibType()) @@ -2294,7 +2294,7 @@ void PrintAST::visitTypeAliasDecl(TypeAliasDecl *decl) { // preserving sugar. llvm::SaveAndRestore setGenericEnv(Options.GenericEnv, decl->getGenericEnvironment()); - printTypeLoc(decl->getUnderlyingTypeLoc()); + printTypeLoc(TypeLoc::withoutLoc(Ty)); printGenericDeclGenericRequirements(decl); } } diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index 977543b864cde..df8b4b216198e 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -232,7 +232,10 @@ class Traversal : public ASTVisitorgetUnderlyingTypeLoc()); + if (auto typerepr = TAD->getUnderlyingTypeRepr()) + if (doIt(typerepr)) + return true; + return false; } bool visitOpaqueTypeDecl(OpaqueTypeDecl *OTD) { diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index c570f65f4ccd8..4f4017861bab0 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -3527,34 +3527,35 @@ SourceRange TypeAliasDecl::getSourceRange() const { return { TypeAliasLoc, getNameLoc() }; } -void TypeAliasDecl::setUnderlyingType(Type underlying) { - setValidationToChecked(); - - // lldb creates global typealiases containing archetypes - // sometimes... - if (underlying->hasArchetype() && isGenericContext()) - underlying = underlying->mapTypeOutOfContext(); - UnderlyingTy.setType(underlying); - - // FIXME -- if we already have an interface type, we're changing the - // underlying type. See the comment in the ProtocolDecl case of - // validateDecl(). - if (!hasInterfaceType()) { - // Set the interface type of this declaration. - ASTContext &ctx = getASTContext(); +void TypeAliasDecl::computeType() { + assert(!hasInterfaceType()); + + // Set the interface type of this declaration. + ASTContext &ctx = getASTContext(); - auto *genericSig = getGenericSignature(); - SubstitutionMap subs; - if (genericSig) - subs = genericSig->getIdentitySubstitutionMap(); + auto *genericSig = getGenericSignature(); + SubstitutionMap subs; + if (genericSig) + subs = genericSig->getIdentitySubstitutionMap(); - Type parent; - auto parentDC = getDeclContext(); - if (parentDC->isTypeContext()) - parent = parentDC->getDeclaredInterfaceType(); - auto sugaredType = TypeAliasType::get(this, parent, subs, underlying); - setInterfaceType(MetatypeType::get(sugaredType, ctx)); - } + Type parent; + auto parentDC = getDeclContext(); + if (parentDC->isTypeContext()) + parent = parentDC->getDeclaredInterfaceType(); + auto sugaredType = TypeAliasType::get(this, parent, subs, getUnderlyingType()); + setInterfaceType(MetatypeType::get(sugaredType, ctx)); +} + +Type TypeAliasDecl::getUnderlyingType() const { + return evaluateOrDefault(getASTContext().evaluator, + UnderlyingTypeRequest{const_cast(this)}, + Type()); +} + +void TypeAliasDecl::setUnderlyingType(Type underlying) { + getASTContext().evaluator.cacheOutput( + UnderlyingTypeRequest{const_cast(this)}, + std::move(underlying)); } UnboundGenericType *TypeAliasDecl::getUnboundGenericType() const { @@ -3571,12 +3572,10 @@ UnboundGenericType *TypeAliasDecl::getUnboundGenericType() const { } Type TypeAliasDecl::getStructuralType() const { - assert(!getGenericParams()); - auto &context = getASTContext(); - return evaluateOrDefault(context.evaluator, - StructuralTypeRequest { const_cast(this) }, - Type()); + return evaluateOrDefault( + context.evaluator, + StructuralTypeRequest{const_cast(this)}, Type()); } Type AbstractTypeParamDecl::getSuperclass() const { diff --git a/lib/AST/DiagnosticEngine.cpp b/lib/AST/DiagnosticEngine.cpp index d6dc1696a17f2..646532e5821d6 100644 --- a/lib/AST/DiagnosticEngine.cpp +++ b/lib/AST/DiagnosticEngine.cpp @@ -379,7 +379,7 @@ static bool isInterestingTypealias(Type type) { // Compatibility aliases are only interesting insofar as their underlying // types are interesting. if (aliasDecl->isCompatibilityAlias()) { - auto underlyingTy = aliasDecl->getUnderlyingTypeLoc().getType(); + auto underlyingTy = aliasDecl->getUnderlyingType(); return isInterestingTypealias(underlyingTy); } diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp index ea2536b296ea8..0adec2fd06a28 100644 --- a/lib/AST/GenericSignatureBuilder.cpp +++ b/lib/AST/GenericSignatureBuilder.cpp @@ -3785,9 +3785,8 @@ PotentialArchetype *GenericSignatureBuilder::realizePotentialArchetype( static Type getStructuralType(TypeDecl *typeDecl) { if (auto typealias = dyn_cast(typeDecl)) { - if (auto resolved = typealias->getUnderlyingTypeLoc().getType()) - return resolved; - + if (typealias->hasInterfaceType()) + return typealias->getDeclaredInterfaceType(); return typealias->getStructuralType(); } @@ -4196,11 +4195,10 @@ ConstraintResult GenericSignatureBuilder::expandConformanceRequirement( out << start; out << type->getFullName() << " == "; if (auto typealias = dyn_cast(type)) { - if (auto underlyingTypeRepr = - typealias->getUnderlyingTypeLoc().getTypeRepr()) + if (auto underlyingTypeRepr = typealias->getUnderlyingTypeRepr()) underlyingTypeRepr->print(out); else - typealias->getUnderlyingTypeLoc().getType().print(out); + typealias->getUnderlyingType().print(out); } else { type->print(out); } diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 3378423f291d9..7d0be9a49fbbb 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -101,6 +101,8 @@ void BuiltinUnit::LookupCache::lookupValue( const_cast(&M)); TAD->setUnderlyingType(Ty); TAD->setAccess(AccessLevel::Public); + TAD->setValidationToChecked(); + TAD->computeType(); Entry = TAD; } } diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index 4e04d2f64f3d3..7cd88bceb3489 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -1813,7 +1813,7 @@ resolveTypeDeclsToNominal(Evaluator &evaluator, // Recognize Swift.AnyObject directly. if (typealias->getName().is("AnyObject")) { // TypeRepr version: Builtin.AnyObject - if (auto typeRepr = typealias->getUnderlyingTypeLoc().getTypeRepr()) { + if (auto typeRepr = typealias->getUnderlyingTypeRepr()) { if (auto compound = dyn_cast(typeRepr)) { auto components = compound->getComponents(); if (components.size() == 2 && @@ -1825,9 +1825,10 @@ resolveTypeDeclsToNominal(Evaluator &evaluator, } // Type version: an empty class-bound existential. - if (auto type = typealias->getUnderlyingTypeLoc().getType()) { - if (type->isAnyObject()) - anyObject = true; + if (typealias->hasInterfaceType()) { + if (auto type = typealias->getUnderlyingType()) + if (type->isAnyObject()) + anyObject = true; } } @@ -2091,7 +2092,7 @@ DirectlyReferencedTypeDecls UnderlyingTypeDeclsReferencedRequest::evaluate( Evaluator &evaluator, TypeAliasDecl *typealias) const { // Prefer syntactic information when we have it. - if (auto typeRepr = typealias->getUnderlyingTypeLoc().getTypeRepr()) { + if (auto typeRepr = typealias->getUnderlyingTypeRepr()) { return directReferencesForTypeRepr(evaluator, typealias->getASTContext(), typeRepr, typealias); } @@ -2099,7 +2100,7 @@ DirectlyReferencedTypeDecls UnderlyingTypeDeclsReferencedRequest::evaluate( // Fall back to semantic types. // FIXME: In the long run, we shouldn't need this. Non-syntactic results // should be cached. - if (auto type = typealias->getUnderlyingTypeLoc().getType()) { + if (auto type = typealias->getUnderlyingType()) { return directReferencesForType(type); } diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 1fd2199ee4839..d9a3e66a0a9bf 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -2659,7 +2659,7 @@ void ClangModuleUnit::getTopLevelDecls(SmallVectorImpl &results) const { auto alias = dyn_cast(importedDecl); if (!alias || !alias->isCompatibilityAlias()) continue; - auto aliasedTy = alias->getUnderlyingTypeLoc().getType(); + auto aliasedTy = alias->getUnderlyingType(); ext = nullptr; importedDecl = nullptr; diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 46d4f796a6aae..a1a8021467421 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -1493,6 +1493,7 @@ static void addSynthesizedTypealias(NominalTypeDecl *nominal, Identifier name, typealias->setAccess(AccessLevel::Public); typealias->setValidationToChecked(); typealias->setImplicit(); + typealias->computeType(); nominal->addMember(typealias); } @@ -2563,6 +2564,8 @@ namespace { /*genericparams*/nullptr, DC); typealias->setUnderlyingType( underlying->getDeclaredInterfaceType()); + typealias->setValidationToChecked(); + typealias->computeType(); Impl.SpecialTypedefNames[Decl->getCanonicalDecl()] = MappedTypeNameKind::DefineAndUse; @@ -2582,6 +2585,8 @@ namespace { /*genericparams*/nullptr, DC); typealias->setUnderlyingType( Impl.SwiftContext.getAnyObjectType()); + typealias->setValidationToChecked(); + typealias->computeType(); Impl.SpecialTypedefNames[Decl->getCanonicalDecl()] = MappedTypeNameKind::DefineAndUse; @@ -2649,7 +2654,9 @@ namespace { Loc, /*genericparams*/nullptr, DC); Result->setUnderlyingType(SwiftType); - + Result->setValidationToChecked(); + Result->computeType(); + // Make Objective-C's 'id' unavailable. if (Impl.SwiftContext.LangOpts.EnableObjCInterop && isObjCId(Decl)) { auto attr = AvailableAttr::createPlatformAgnostic( @@ -2943,6 +2950,8 @@ namespace { C.Id_ErrorType, loc, /*genericparams=*/nullptr, enumDecl); alias->setUnderlyingType(errorWrapper->getDeclaredInterfaceType()); + alias->setValidationToChecked(); + alias->computeType(); enumDecl->addMember(alias); // Add the 'Code' enum to the error wrapper. @@ -4027,7 +4036,9 @@ namespace { Loc, /*genericparams*/nullptr, DC); Result->setUnderlyingType(SwiftTypeDecl->getDeclaredInterfaceType()); - + Result->setValidationToChecked(); + Result->computeType(); + return Result; } @@ -5163,6 +5174,8 @@ namespace { } typealias->setUnderlyingType(typeDecl->getDeclaredInterfaceType()); + typealias->setValidationToChecked(); + typealias->computeType(); return typealias; } @@ -5398,7 +5411,9 @@ Decl *SwiftDeclConverter::importCompatibilityTypeAlias( } alias->setUnderlyingType(typeDecl->getDeclaredInterfaceType()); - + alias->setValidationToChecked(); + alias->computeType(); + // Record that this is the official version of this declaration. Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = alias; markAsVariant(alias, correctSwiftName); @@ -8234,7 +8249,7 @@ ClangImporter::Implementation::createConstant(Identifier name, DeclContext *dc, auto maxFloatTypeDecl = context.get_MaxBuiltinFloatTypeDecl(); floatExpr->setBuiltinType( - maxFloatTypeDecl->getUnderlyingTypeLoc().getType()); + maxFloatTypeDecl->getUnderlyingType()); auto *floatDecl = literalType->getAnyNominal(); floatExpr->setBuiltinInitializer( diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index a716698f704ad..28d8fcafe6b64 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -2794,7 +2794,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { addLeadingDot(Builder); Builder.addTextChunk(TAD->getName().str()); if (TAD->hasInterfaceType()) { - auto underlyingType = TAD->getUnderlyingTypeLoc().getType(); + auto underlyingType = TAD->getUnderlyingType(); if (underlyingType->hasError()) { Type parentType; if (auto nominal = TAD->getDeclContext()->getSelfNominalTypeDecl()) { diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp index c086a5d1ae47f..17123e9b5daa0 100644 --- a/lib/IRGen/IRGenDebugInfo.cpp +++ b/lib/IRGen/IRGenDebugInfo.cpp @@ -734,6 +734,8 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { NoLoc, NoLoc, IGM.Context.getIdentifier(ArchetypeName), NoLoc, /*genericparams*/ nullptr, IGM.Context.TheBuiltinModule); Entry->setUnderlyingType(IGM.Context.TheRawPointerType); + Entry->setValidationToChecked(); + Entry->computeType(); return Entry; } diff --git a/lib/Index/Index.cpp b/lib/Index/Index.cpp index 5c21b602553f3..33505902916ae 100644 --- a/lib/Index/Index.cpp +++ b/lib/Index/Index.cpp @@ -925,7 +925,7 @@ bool IndexSwiftASTWalker::reportRelatedTypeRef(const TypeLoc &Ty, SymbolRoleSet IndexSymbol Info; if (!reportRef(TAD, IdLoc, Info, None)) return false; - if (auto Ty = TAD->getUnderlyingTypeLoc().getType()) { + if (auto Ty = TAD->getUnderlyingType()) { NTD = Ty->getAnyNominal(); isImplicit = true; } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 599d3ee5b6c6f..9536dc574a779 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -4198,7 +4198,7 @@ parseDeclTypeAlias(Parser::ParseDeclOptions Flags, DeclAttributes &Attributes) { Status |= UnderlyingTy; } - TAD->getUnderlyingTypeLoc() = UnderlyingTy.getPtrOrNull(); + TAD->setUnderlyingTypeRepr(UnderlyingTy.getPtrOrNull()); TAD->getAttrs() = Attributes; // Parse a 'where' clause if present, adding it to our GenericParamList. diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 1a11940931db0..a8abf52aee3f9 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -1927,7 +1927,7 @@ namespace { } tc.validateDecl(maxFloatTypeDecl); - auto maxType = maxFloatTypeDecl->getUnderlyingTypeLoc().getType(); + auto maxType = maxFloatTypeDecl->getUnderlyingType(); DeclName initName(tc.Context, DeclBaseName::createConstructor(), { tc.Context.Id_floatLiteral }); diff --git a/lib/Sema/CalleeCandidateInfo.cpp b/lib/Sema/CalleeCandidateInfo.cpp index 7cccb629d1adf..5c71eac3ab4cb 100644 --- a/lib/Sema/CalleeCandidateInfo.cpp +++ b/lib/Sema/CalleeCandidateInfo.cpp @@ -594,7 +594,7 @@ void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn, CS.DC, instanceType, NameLookupFlags::IgnoreAccessControl); for (auto ctor : ctors) { if (!ctor.getValueDecl()->hasInterfaceType()) - CS.getTypeChecker().validateDeclForNameLookup(ctor.getValueDecl()); + CS.getTypeChecker().validateDecl(ctor.getValueDecl()); if (ctor.getValueDecl()->hasInterfaceType()) candidates.push_back({ ctor.getValueDecl(), 1 }); } diff --git a/lib/Sema/NameBinding.cpp b/lib/Sema/NameBinding.cpp index 0d532c8713f06..b5f713c21025e 100644 --- a/lib/Sema/NameBinding.cpp +++ b/lib/Sema/NameBinding.cpp @@ -333,7 +333,7 @@ void NameBinder::addImport( diag::imported_decl_is_wrong_kind_typealias, typealias->getDescriptiveKind(), TypeAliasType::get(typealias, Type(), SubstitutionMap(), - typealias->getUnderlyingTypeLoc().getType()), + typealias->getUnderlyingType()), getImportKindString(ID->getImportKind()))); } else { emittedDiag.emplace(diagnose(ID, diag::imported_decl_is_wrong_kind, diff --git a/lib/Sema/TypeCheckAccess.cpp b/lib/Sema/TypeCheckAccess.cpp index 57322cce77a19..5d9f6360567c5 100644 --- a/lib/Sema/TypeCheckAccess.cpp +++ b/lib/Sema/TypeCheckAccess.cpp @@ -572,7 +572,8 @@ class AccessControlChecker : public AccessControlCheckerBase, void visitTypeAliasDecl(TypeAliasDecl *TAD) { checkGenericParamAccess(TAD->getGenericParams(), TAD); - checkTypeAccess(TAD->getUnderlyingTypeLoc(), TAD, /*mayBeInferred*/false, + checkTypeAccess(TAD->getUnderlyingType(), + TAD->getUnderlyingTypeRepr(), TAD, /*mayBeInferred*/false, [&](AccessScope typeAccessScope, const TypeRepr *complainRepr, DowngradeToWarning downgradeToWarning) { @@ -1194,7 +1195,8 @@ class UsableFromInlineChecker : public AccessControlCheckerBase, void visitTypeAliasDecl(TypeAliasDecl *TAD) { checkGenericParamAccess(TAD->getGenericParams(), TAD); - checkTypeAccess(TAD->getUnderlyingTypeLoc(), TAD, /*mayBeInferred*/false, + checkTypeAccess(TAD->getUnderlyingType(), + TAD->getUnderlyingTypeRepr(), TAD, /*mayBeInferred*/false, [&](AccessScope typeAccessScope, const TypeRepr *complainRepr, DowngradeToWarning downgradeToWarning) { @@ -1832,7 +1834,8 @@ class ExportabilityChecker : public DeclVisitor { void visitTypeAliasDecl(TypeAliasDecl *TAD) { checkGenericParams(TAD->getGenericParams(), TAD); - checkType(TAD->getUnderlyingTypeLoc(), TAD, getDiagnoseCallback(TAD), + checkType(TAD->getUnderlyingType(), + TAD->getUnderlyingTypeRepr(), TAD, getDiagnoseCallback(TAD), getDiagnoseCallback(TAD)); } diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index ad318c6051f46..98b67d1475ebc 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2470,8 +2470,11 @@ class DeclChecker : public DeclVisitor { // Force the generic signature to be computed in case it emits diagnostics. (void)TAD->getGenericSignature(); - + // Force computing the underlying type in case it emits diagnostics. + (void)TAD->getUnderlyingType(); + checkAccessControl(TC, TAD); + } void visitOpaqueTypeDecl(OpaqueTypeDecl *OTD) { @@ -3469,37 +3472,36 @@ IsImplicitlyUnwrappedOptionalRequest::evaluate(Evaluator &evaluator, } /// Validate the underlying type of the given typealias. -static void validateTypealiasType(TypeChecker &tc, TypeAliasDecl *typeAlias) { - TypeResolutionOptions options( - (typeAlias->getGenericParams() ? - TypeResolverContext::GenericTypeAliasDecl : - TypeResolverContext::TypeAliasDecl)); +llvm::Expected +UnderlyingTypeRequest::evaluate(Evaluator &evaluator, + TypeAliasDecl *typeAlias) const { + TypeResolutionOptions options((typeAlias->getGenericParams() + ? TypeResolverContext::GenericTypeAliasDecl + : TypeResolverContext::TypeAliasDecl)); if (!typeAlias->getDeclContext()->isCascadingContextForLookup( - /*functionsAreNonCascading*/true)) { - options |= TypeResolutionFlags::KnownNonCascadingDependency; + /*functionsAreNonCascading*/ true)) { + options |= TypeResolutionFlags::KnownNonCascadingDependency; } // This can happen when code completion is attempted inside // of typealias underlying type e.g. `typealias F = () -> Int#^TOK^#` - auto underlyingType = typeAlias->getUnderlyingTypeLoc(); - if (underlyingType.isNull()) { - typeAlias->getUnderlyingTypeLoc().setInvalidType(tc.Context); - typeAlias->setInterfaceType(ErrorType::get(tc.Context)); - return; + auto *underlyingRepr = typeAlias->getUnderlyingTypeRepr(); + if (!underlyingRepr) { + typeAlias->setInvalid(); + return ErrorType::get(typeAlias->getASTContext()); } - if (TypeChecker::validateType(tc.Context, typeAlias->getUnderlyingTypeLoc(), - TypeResolution::forInterface(typeAlias, &tc), + if (TypeChecker::validateType(typeAlias->getASTContext(), + typeAlias->getUnderlyingTypeLoc(), + TypeResolution::forInterface(typeAlias), options)) { typeAlias->setInvalid(); - typeAlias->getUnderlyingTypeLoc().setInvalidType(tc.Context); + return ErrorType::get(typeAlias->getASTContext()); } - - typeAlias->setUnderlyingType(typeAlias->getUnderlyingTypeLoc().getType()); + return ty; } - /// Bind the given function declaration, which declares an operator, to the corresponding operator declaration. llvm::Expected FunctionOperatorRequest::evaluate(Evaluator &evaluator, FuncDecl *FD) const { @@ -3812,9 +3814,13 @@ void TypeChecker::validateDecl(ValueDecl *D) { case DeclKind::TypeAlias: { auto typeAlias = cast(D); - // Check generic parameters, if needed. + DeclValidationRAII IBV(typeAlias); - validateTypealiasType(*this, typeAlias); + + // Finally, set the interface type. + if (!typeAlias->hasInterfaceType()) + typeAlias->computeType(); + break; } @@ -4327,11 +4333,35 @@ EmittedMembersRequest::evaluate(Evaluator &evaluator, return CD->getMembers(); } +<<<<<<< HEAD bool TypeChecker::isPassThroughTypealias(TypeAliasDecl *typealias) { // Pass-through only makes sense when the typealias refers to a nominal // type. Type underlyingType = typealias->getUnderlyingTypeLoc().getType(); auto nominal = underlyingType->getAnyNominal(); +======= +/// Determine whether this is a "pass-through" typealias, which has the +/// same type parameters as the nominal type it references and specializes +/// the underlying nominal type with exactly those type parameters. +/// For example, the following typealias \c GX is a pass-through typealias: +/// +/// \code +/// struct X { } +/// typealias GX = X +/// \endcode +/// +/// whereas \c GX2 and \c GX3 are not pass-through because \c GX2 has +/// different type parameters and \c GX3 doesn't pass its type parameters +/// directly through. +/// +/// \code +/// typealias GX2 = X +/// typealias GX3 = X +/// \endcode +static bool isPassThroughTypealias(TypeAliasDecl *typealias, + Type underlyingType, + NominalTypeDecl *nominal) { +>>>>>>> Separate computing interface types and underlying types if (!nominal) return false; // Check that the nominal type and the typealias are either both generic @@ -4380,6 +4410,138 @@ bool TypeChecker::isPassThroughTypealias(TypeAliasDecl *typealias) { }); } +<<<<<<< HEAD +======= +/// Form the interface type of an extension from the raw type and the +/// extension's list of generic parameters. +static Type formExtensionInterfaceType( + TypeChecker &tc, ExtensionDecl *ext, + Type type, + GenericParamList *genericParams, + SmallVectorImpl &sameTypeReqs, + bool &mustInferRequirements) { + if (type->is()) + return type; + + // Find the nominal type declaration and its parent type. + if (type->is()) + type = type->getCanonicalType(); + + Type parentType = type->getNominalParent(); + GenericTypeDecl *genericDecl = type->getAnyGeneric(); + + // Reconstruct the parent, if there is one. + if (parentType) { + // Build the nested extension type. + auto parentGenericParams = genericDecl->getGenericParams() + ? genericParams->getOuterParameters() + : genericParams; + parentType = + formExtensionInterfaceType(tc, ext, parentType, parentGenericParams, + sameTypeReqs, mustInferRequirements); + } + + // Find the nominal type. + auto nominal = dyn_cast(genericDecl); + auto typealias = dyn_cast(genericDecl); + if (!nominal) { + Type underlyingType = typealias->getUnderlyingTypeLoc().getType(); + nominal = underlyingType->getNominalOrBoundGenericNominal(); + } + + // Form the result. + Type resultType; + SmallVector genericArgs; + if (!nominal->isGeneric() || isa(nominal)) { + resultType = NominalType::get(nominal, parentType, + nominal->getASTContext()); + } else { + auto currentBoundType = type->getAs(); + + // Form the bound generic type with the type parameters provided. + unsigned gpIndex = 0; + for (auto gp : *genericParams) { + SWIFT_DEFER { ++gpIndex; }; + + auto gpType = gp->getDeclaredInterfaceType(); + genericArgs.push_back(gpType); + + if (currentBoundType) { + sameTypeReqs.emplace_back(RequirementKind::SameType, gpType, + currentBoundType->getGenericArgs()[gpIndex]); + } + } + + resultType = BoundGenericType::get(nominal, parentType, genericArgs); + } + + // If we have a typealias, try to form type sugar. + if (typealias && isPassThroughTypealias(typealias, typealias->getUnderlyingType(), nominal)) { + auto typealiasSig = typealias->getGenericSignature(); + SubstitutionMap subMap; + if (typealiasSig) { + subMap = typealiasSig->getIdentitySubstitutionMap(); + + mustInferRequirements = true; + } + + resultType = TypeAliasType::get(typealias, parentType, subMap, + resultType); + } + + return resultType; +} + +/// Retrieve the generic parameter depth of the extended type. +static unsigned getExtendedTypeGenericDepth(ExtensionDecl *ext) { + auto nominal = ext->getSelfNominalTypeDecl(); + if (!nominal) return static_cast(-1); + + auto sig = nominal->getGenericSignatureOfContext(); + if (!sig) return static_cast(-1); + + return sig->getGenericParams().back()->getDepth(); +} + +/// Check the generic parameters of an extension, recursively handling all of +/// the parameter lists within the extension. +static GenericSignature * +checkExtensionGenericParams(TypeChecker &tc, ExtensionDecl *ext, + GenericParamList *genericParams) { + assert(!ext->getGenericEnvironment()); + + // Form the interface type of the extension. + bool mustInferRequirements = false; + SmallVector sameTypeReqs; + Type extInterfaceType = + formExtensionInterfaceType(tc, ext, ext->getExtendedType(), + genericParams, sameTypeReqs, + mustInferRequirements); + + assert(genericParams && "Missing generic parameters?"); + + auto cannotReuseNominalSignature = [&]() -> bool { + const auto finalDepth = genericParams->getParams().back()->getDepth(); + return mustInferRequirements + || !sameTypeReqs.empty() + || ext->getTrailingWhereClause() + || (getExtendedTypeGenericDepth(ext) != finalDepth); + }; + + // Re-use the signature of the type being extended by default. + if (cannotReuseNominalSignature()) { + return TypeChecker::checkGenericSignature( + genericParams, ext, + /*parent signature*/ nullptr, + /*allowConcreteGenericParams=*/true, + sameTypeReqs, + {TypeLoc{nullptr, extInterfaceType}}); + } + + return ext->getSelfNominalTypeDecl()->getGenericSignatureOfContext(); +} + +>>>>>>> Separate computing interface types and underlying types static bool isNonGenericTypeAliasType(Type type) { // A non-generic typealias can extend a specialized type. if (auto *aliasType = dyn_cast(type.getPointer())) @@ -4412,11 +4574,28 @@ ExtendedTypeRequest::evaluate(Evaluator &eval, ExtensionDecl *ext) const { // Hack to allow extending a generic typealias. if (auto *unboundGeneric = extendedType->getAs()) { if (auto *aliasDecl = dyn_cast(unboundGeneric->getDecl())) { +<<<<<<< HEAD auto extendedNominal = aliasDecl->getDeclaredInterfaceType()->getAnyNominal(); if (extendedNominal) return TypeChecker::isPassThroughTypealias(aliasDecl) ? extendedType : extendedNominal->getDeclaredType(); +======= + // Nested Hack to break cycles if this is called before validation has + // finished. + if (aliasDecl->hasInterfaceType()) { + auto extendedNominal = aliasDecl->getDeclaredInterfaceType()->getAnyNominal(); + if (extendedNominal) + return isPassThroughTypealias(aliasDecl, aliasDecl->getUnderlyingType(), extendedNominal) + ? extendedType + : extendedNominal->getDeclaredType(); + } else { + if (auto ty = aliasDecl->getStructuralType()->getAs()) + return isPassThroughTypealias(aliasDecl, ty, ty->getDecl()) + ? extendedType + : ty->getDecl()->getDeclaredType(); + } +>>>>>>> Separate computing interface types and underlying types } } diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index cfc38398569bd..475a789d3e40f 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -2480,7 +2480,9 @@ void ConformanceChecker::recordTypeWitness(AssociatedTypeDecl *assocType, DC); aliasDecl->setGenericSignature(DC->getGenericSignatureOfContext()); aliasDecl->setUnderlyingType(type); - + aliasDecl->setValidationToChecked(); + aliasDecl->computeType(); + aliasDecl->setImplicit(); if (type->hasError()) aliasDecl->setInvalid(); diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index abe05c5118fd8..8d8911c9dfbb8 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -485,12 +485,10 @@ TypeChecker::getDynamicBridgedThroughObjCClass(DeclContext *dc, return Context.getBridgedToObjC(dc, valueType); } -Type TypeChecker::resolveTypeInContext( - TypeDecl *typeDecl, - DeclContext *foundDC, - TypeResolution resolution, - TypeResolutionOptions options, - bool isSpecialized) { +Type TypeChecker::resolveTypeInContext(TypeDecl *typeDecl, DeclContext *foundDC, + TypeResolution resolution, + TypeResolutionOptions options, + bool isSpecialized) { auto fromDC = resolution.getDeclContext(); ASTContext &ctx = fromDC->getASTContext(); @@ -498,7 +496,7 @@ Type TypeChecker::resolveTypeInContext( // If we found a generic parameter, map to the archetype if there is one. if (auto genericParam = dyn_cast(typeDecl)) { return resolution.mapTypeIntoContext( - genericParam->getDeclaredInterfaceType()); + genericParam->getDeclaredInterfaceType()); } if (!isSpecialized) { @@ -506,19 +504,18 @@ Type TypeChecker::resolveTypeInContext( // a generic type with no generic arguments or a non-generic type, use the // type within the context. if (auto *nominalType = dyn_cast(typeDecl)) { - for (auto *parentDC = fromDC; - !parentDC->isModuleScopeContext(); + for (auto *parentDC = fromDC; !parentDC->isModuleScopeContext(); parentDC = parentDC->getParent()) { auto *parentNominal = parentDC->getSelfNominalTypeDecl(); if (parentNominal == nominalType) return resolution.mapTypeIntoContext( - parentDC->getDeclaredInterfaceType()); + parentDC->getDeclaredInterfaceType()); if (isa(parentDC)) { auto *extendedType = parentNominal; while (extendedType != nullptr) { if (extendedType == nominalType) return resolution.mapTypeIntoContext( - extendedType->getDeclaredInterfaceType()); + extendedType->getDeclaredInterfaceType()); extendedType = extendedType->getParent()->getSelfNominalTypeDecl(); } } @@ -528,26 +525,39 @@ Type TypeChecker::resolveTypeInContext( // If we're inside an extension of a type alias, allow the type alias to be // referenced without generic arguments as well. if (auto *aliasDecl = dyn_cast(typeDecl)) { - for (auto *parentDC = fromDC; - !parentDC->isModuleScopeContext(); - parentDC = parentDC->getParent()) { + for (auto *parentDC = fromDC; !parentDC->isModuleScopeContext(); + parentDC = parentDC->getParent()) { if (auto *ext = dyn_cast(parentDC)) { auto extendedType = ext->getExtendedType(); - if (auto *unboundGeneric = dyn_cast(extendedType.getPointer())) { - if (auto *ugAliasDecl = dyn_cast(unboundGeneric->getAnyGeneric())) { - if (ugAliasDecl == aliasDecl) + if (auto *unboundGeneric = + dyn_cast(extendedType.getPointer())) { + if (auto *ugAliasDecl = + dyn_cast(unboundGeneric->getAnyGeneric())) { + if (ugAliasDecl == aliasDecl) { + if (resolution.getStage() == TypeResolutionStage::Structural && + !aliasDecl->hasInterfaceType()) { + return resolution.mapTypeIntoContext( + aliasDecl->getStructuralType()); + } return resolution.mapTypeIntoContext( - aliasDecl->getDeclaredInterfaceType()); + aliasDecl->getDeclaredInterfaceType()); + } extendedType = unboundGeneric->getParent(); continue; } } - if (auto *aliasType = dyn_cast(extendedType.getPointer())) { - if (aliasType->getDecl() == aliasDecl) + if (auto *aliasType = + dyn_cast(extendedType.getPointer())) { + if (aliasType->getDecl() == aliasDecl) { + if (resolution.getStage() == TypeResolutionStage::Structural && + !aliasDecl->hasInterfaceType()) { + return resolution.mapTypeIntoContext( + aliasDecl->getStructuralType()); + } return resolution.mapTypeIntoContext( aliasDecl->getDeclaredInterfaceType()); - + } extendedType = aliasType->getParent(); continue; } @@ -566,9 +576,13 @@ Type TypeChecker::resolveTypeInContext( if (aliasDecl->getGenericParams()) return aliasDecl->getUnboundGenericType(); - // Otherwise, simply return the underlying type. + // Otherwise, return the appropriate type. + if (resolution.getStage() == TypeResolutionStage::Structural && + !aliasDecl->hasInterfaceType()) { + return resolution.mapTypeIntoContext(aliasDecl->getStructuralType()); + } return resolution.mapTypeIntoContext( - aliasDecl->getDeclaredInterfaceType()); + aliasDecl->getDeclaredInterfaceType()); } // When a nominal type used outside its context, return the unbound @@ -595,13 +609,12 @@ Type TypeChecker::resolveTypeInContext( if (!foundDC->getDeclaredInterfaceType()) return ErrorType::get(ctx); - selfType = resolution.mapTypeIntoContext( - foundDC->getDeclaredInterfaceType()); + selfType = + resolution.mapTypeIntoContext(foundDC->getDeclaredInterfaceType()); } else { // Otherwise, we want the protocol 'Self' type for // substituting into alias types and associated types. - selfType = resolution.mapTypeIntoContext( - foundDC->getSelfInterfaceType()); + selfType = resolution.mapTypeIntoContext(foundDC->getSelfInterfaceType()); if (selfType->is()) { if (typeDecl->getDeclContext()->getSelfProtocolDecl()) { @@ -617,8 +630,8 @@ Type TypeChecker::resolveTypeInContext( // the Collection.SubSequence default, even when the conforming // type wants to conform to Collection. if (resolution.getStage() == TypeResolutionStage::Structural) { - return resolution.resolveSelfAssociatedType( - selfType, foundDC, typeDecl->getName()); + return resolution.resolveSelfAssociatedType(selfType, foundDC, + typeDecl->getName()); } else if (auto assocType = dyn_cast(typeDecl)) { typeDecl = assocType->getAssociatedTypeAnchor(); } @@ -642,10 +655,10 @@ Type TypeChecker::resolveTypeInContext( } } } - + // Finally, substitute the base type into the member type. - return substMemberTypeWithBase(fromDC->getParentModule(), typeDecl, - selfType, resolution.usesArchetypes()); + return substMemberTypeWithBase(fromDC->getParentModule(), typeDecl, selfType, + resolution.usesArchetypes()); } static TypeResolutionOptions @@ -884,7 +897,7 @@ Type TypeChecker::applyUnboundGenericArguments( // later. auto typealias = dyn_cast(decl); if (typealias) { - resultType = typealias->getUnderlyingTypeLoc().getType(); + resultType = typealias->getUnderlyingType(); } // Apply the substitution map to the interface type of the declaration. @@ -962,8 +975,7 @@ static void maybeDiagnoseBadConformanceRef(DeclContext *dc, /// Returns a valid type or ErrorType in case of an error. static Type resolveTypeDecl(TypeDecl *typeDecl, SourceLoc loc, - DeclContext *foundDC, - TypeResolution resolution, + DeclContext *foundDC, TypeResolution resolution, GenericIdentTypeRepr *generic, TypeResolutionOptions options) { auto fromDC = resolution.getDeclContext(); @@ -973,9 +985,19 @@ static Type resolveTypeDecl(TypeDecl *typeDecl, SourceLoc loc, auto &diags = ctx.Diags; auto lazyResolver = ctx.getLazyResolver(); + // Hack: Don't validate nested typealiases if we only need the structural + // type. + auto prevalidatingAlias = [](TypeDecl *typeDecl, TypeResolution res) { + return isa(typeDecl) + && !typeDecl->hasInterfaceType() + && typeDecl->getDeclContext()->isTypeContext() + && res.getStage() == TypeResolutionStage::Structural; + }; + // Don't validate nominal type declarations during extension binding. - if (!options.is(TypeResolverContext::ExtensionBinding) || - !isa(typeDecl)) { + if ((!options.is(TypeResolverContext::ExtensionBinding) || + !isa(typeDecl)) && + !prevalidatingAlias(typeDecl, resolution)) { // Validate the declaration. if (lazyResolver && !typeDecl->hasInterfaceType()) lazyResolver->resolveDeclSignature(typeDecl); @@ -983,18 +1005,16 @@ static Type resolveTypeDecl(TypeDecl *typeDecl, SourceLoc loc, // If we were not able to validate recursively, bail out. if (!typeDecl->hasInterfaceType()) { diags.diagnose(loc, diag::recursive_decl_reference, - typeDecl->getDescriptiveKind(), typeDecl->getName()); - typeDecl->diagnose(diag::kind_declared_here, - DescriptiveDeclKind::Type); + typeDecl->getDescriptiveKind(), typeDecl->getName()); + typeDecl->diagnose(diag::kind_declared_here, DescriptiveDeclKind::Type); return ErrorType::get(ctx); } } // Resolve the type declaration to a specific type. How this occurs // depends on the current context and where the type was found. - Type type = - TypeChecker::resolveTypeInContext(typeDecl, foundDC, resolution, options, - generic); + Type type = TypeChecker::resolveTypeInContext(typeDecl, foundDC, resolution, + options, generic); if (type->is() && !generic && !options.is(TypeResolverContext::TypeAliasDecl) && @@ -1005,8 +1025,7 @@ static Type resolveTypeDecl(TypeDecl *typeDecl, SourceLoc loc, if (type->hasError() && foundDC && (isa(typeDecl) || isa(typeDecl))) { - maybeDiagnoseBadConformanceRef(fromDC, - foundDC->getDeclaredInterfaceType(), + maybeDiagnoseBadConformanceRef(fromDC, foundDC->getDeclaredInterfaceType(), loc, typeDecl); } @@ -3437,7 +3456,7 @@ Type TypeChecker::substMemberTypeWithBase(ModuleDecl *module, } Type resultType; - auto memberType = aliasDecl ? aliasDecl->getUnderlyingTypeLoc().getType() + auto memberType = aliasDecl ? aliasDecl->getUnderlyingType() : member->getDeclaredInterfaceType(); SubstitutionMap subs; if (baseTy) { diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 9fec251ba33ed..b02c5da5ef3b0 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -2287,10 +2287,22 @@ class swift::DeclDeserializer { SourceLoc(), genericParams, DC); declOrOffset = alias; - alias->setGenericSignature(MF.getGenericSignature(genericSigID)); - - alias->setUnderlyingType(MF.getType(underlyingTypeID)); + auto *genericSig = MF.getGenericSignature(genericSigID); + alias->setGenericSignature(genericSig); + auto underlying = MF.getType(underlyingTypeID); + alias->setUnderlyingType(underlying); + SubstitutionMap subs; + if (genericSig) { + subs = genericSig->getIdentitySubstitutionMap(); + } + Type parent; + if (DC->isTypeContext()) + parent = DC->getDeclaredInterfaceType(); + auto sugaredType = TypeAliasType::get(alias, parent, subs, underlying); + alias->setInterfaceType(MetatypeType::get(sugaredType, ctx)); + alias->setValidationToChecked(); + if (auto accessLevel = getActualAccessLevel(rawAccessLevel)) alias->setAccess(*accessLevel); else @@ -4395,7 +4407,7 @@ class swift::TypeDeserializer { // Look through compatibility aliases that are now unavailable. if (alias->getAttrs().isUnavailable(ctx) && alias->isCompatibilityAlias()) { - return alias->getUnderlyingTypeLoc().getType(); + return alias->getUnderlyingType(); } return alias->getDeclaredInterfaceType(); @@ -4463,7 +4475,7 @@ class swift::TypeDeserializer { if (alias && alias->getAttrs().isUnavailable(ctx) && alias->isCompatibilityAlias()) { - return alias->getUnderlyingTypeLoc().getType().subst(subMap); + return alias->getUnderlyingType().subst(subMap); } auto parentType = parentTypeOrError.get(); @@ -4491,7 +4503,7 @@ class swift::TypeDeserializer { // using the Type wrapper. const TypeBase *underlyingTy = nullptr; while (alias->isCompatibilityAlias()) { - underlyingTy = alias->getUnderlyingTypeLoc().getType().getPointer(); + underlyingTy = alias->getUnderlyingType().getPointer(); // If the underlying type is itself a typealias, it might be another // compatibility alias, meaning we need to go around the loop again. diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 8069509646f36..41b5d95cae01b 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -2797,7 +2797,7 @@ class Serializer::DeclSerializer : public DeclVisitor { auto contextID = S.addDeclContextRef(typeAlias->getDeclContext()); - auto underlying = typeAlias->getUnderlyingTypeLoc().getType(); + auto underlying = typeAlias->getUnderlyingType(); llvm::SmallSetVector dependencies; collectDependenciesFromType(dependencies, underlying->getCanonicalType(), @@ -3717,7 +3717,7 @@ class Serializer::TypeSerializer : public TypeVisitor { void visitTypeAliasType(const TypeAliasType *alias) { using namespace decls_block; const TypeAliasDecl *typeAlias = alias->getDecl(); - auto underlyingType = typeAlias->getUnderlyingTypeLoc().getType(); + auto underlyingType = typeAlias->getUnderlyingType(); unsigned abbrCode = S.DeclTypeAbbrCodes[TypeAliasTypeLayout::Code]; TypeAliasTypeLayout::emitRecord( From d5c014b8e491b1acf5b306c28bb5f03e92709dca Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 13 Sep 2019 11:14:12 -0700 Subject: [PATCH 045/199] Remove validateDeclForNameLookup Flush it and the early validation hack now that we can delay computing the underlying interface type on demand and have taught type resolution to honor the structural type of a typealias. This changes the way requirement signatures are spelled as a side effect. --- lib/Sema/TypeCheckAttr.cpp | 6 +- lib/Sema/TypeCheckDecl.cpp | 286 +----------------- lib/Sema/TypeCheckGeneric.cpp | 4 +- lib/Sema/TypeCheckPattern.cpp | 2 +- lib/Sema/TypeChecker.h | 9 +- test/Generics/protocol_type_aliases.swift | 4 +- test/Generics/requirement_inference.swift | 2 +- .../ModuleAnalyzerNodes.cpp | 2 +- tools/swift-ide-test/ModuleAPIDiff.cpp | 2 +- .../0145-sr7097.swift | 2 +- 10 files changed, 21 insertions(+), 298 deletions(-) diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 662fb95a854fa..b786eaae1d704 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -1070,7 +1070,7 @@ bool swift::isValidDynamicCallableMethod(FuncDecl *decl, DeclContext *DC, // `ExpressibleByStringLiteral`. // `D.Value` and the return type can be arbitrary. - TC.validateDeclForNameLookup(decl); + TC.validateDecl(decl); auto paramList = decl->getParameters(); if (paramList->size() != 1 || paramList->get(0)->isVariadic()) return false; auto argType = paramList->get(0)->getType(); @@ -1241,7 +1241,7 @@ visitDynamicMemberLookupAttr(DynamicMemberLookupAttr *attr) { auto oneCandidate = candidates.front().getValueDecl(); candidates.filter([&](LookupResultEntry entry, bool isOuter) -> bool { auto cand = cast(entry.getValueDecl()); - TC.validateDeclForNameLookup(cand); + TC.validateDecl(cand); return isValidDynamicMemberLookupSubscript(cand, decl, TC); }); @@ -1264,7 +1264,7 @@ visitDynamicMemberLookupAttr(DynamicMemberLookupAttr *attr) { // Validate the candidates while ignoring the label. newCandidates.filter([&](const LookupResultEntry entry, bool isOuter) { auto cand = cast(entry.getValueDecl()); - TC.validateDeclForNameLookup(cand); + TC.validateDecl(cand); return isValidDynamicMemberLookupSubscript(cand, decl, TC, /*ignoreLabel*/ true); }); diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 98b67d1475ebc..b03b334b477a6 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -3861,34 +3861,6 @@ void TypeChecker::validateDecl(ValueDecl *D) { (void)proto->getGenericSignature(); proto->setSignatureIsValidated(); - // See the comment in validateDeclForNameLookup(); we may have validated - // the alias before we built the protocol's generic environment. - // - // FIXME: Hopefully this can all go away with the ITC. - for (auto member : proto->getMembers()) { - if (auto *aliasDecl = dyn_cast(member)) { - if (!aliasDecl->isGeneric()) { - // FIXME: Force creation of the protocol's generic environment now. - (void) proto->getGenericEnvironment(); - - // The generic environment didn't exist until now, we may have - // unresolved types we will need to deal with, and need to record the - // appropriate substitutions for that environment. Wipe out the types - // and validate them again. - aliasDecl->getUnderlyingTypeLoc().setType(Type()); - aliasDecl->setInterfaceType(Type()); - - // Check generic parameters, if needed. - if (aliasDecl->hasValidationStarted()) { - validateTypealiasType(*this, aliasDecl); - } else { - DeclValidationRAII IBV(aliasDecl); - validateTypealiasType(*this, aliasDecl); - } - } - } - } - break; } @@ -4209,90 +4181,6 @@ void TypeChecker::validateDecl(ValueDecl *D) { assert(D->hasValidSignature()); } -void TypeChecker::validateDeclForNameLookup(ValueDecl *D) { - // Validate the context. - auto dc = D->getDeclContext(); - if (auto nominal = dyn_cast(dc)) { - validateDeclForNameLookup(nominal); - if (!nominal->hasInterfaceType()) - return; - } else if (auto ext = dyn_cast(dc)) { - validateExtension(ext); - if (!ext->hasValidSignature()) - return; - } - - switch (D->getKind()) { - case DeclKind::Protocol: { - auto proto = cast(D); - if (proto->hasInterfaceType()) - return; - proto->computeType(); - - break; - } - case DeclKind::AssociatedType: { - auto assocType = cast(D); - if (assocType->hasInterfaceType()) - return; - assocType->computeType(); - break; - } - case DeclKind::TypeAlias: { - auto typealias = cast(D); - if (typealias->getUnderlyingTypeLoc().getType()) - return; - - // Perform earlier validation of typealiases in protocols. - if (isa(dc)) { - if (!typealias->getGenericParams()) { - if (typealias->isBeingValidated()) return; - - auto helper = [&] { - TypeResolutionOptions options( - (typealias->getGenericParams() ? - TypeResolverContext::GenericTypeAliasDecl : - TypeResolverContext::TypeAliasDecl)); - auto &underlyingTL = typealias->getUnderlyingTypeLoc(); - if (underlyingTL.isNull() || - TypeChecker::validateType(Context, - underlyingTL, - TypeResolution::forStructural(typealias), - options)) { - typealias->setInvalid(); - underlyingTL.setInvalidType(Context); - } - - typealias->setUnderlyingType(underlyingTL.getType()); - - // Note that this doesn't set the generic environment of the alias yet, - // because we haven't built one for the protocol. - // - // See how validateDecl() sets the generic environment on alias members - // explicitly. - // - // FIXME: Hopefully this can all go away with the ITC. - }; - - if (typealias->hasValidationStarted()) { - helper(); - } else { - DeclValidationRAII IBV(typealias); - helper(); - } - - return; - } - } - LLVM_FALLTHROUGH; - } - - default: - validateDecl(D); - break; - } -} - llvm::Expected EmittedMembersRequest::evaluate(Evaluator &evaluator, ClassDecl *CD) const { @@ -4333,35 +4221,11 @@ EmittedMembersRequest::evaluate(Evaluator &evaluator, return CD->getMembers(); } -<<<<<<< HEAD -bool TypeChecker::isPassThroughTypealias(TypeAliasDecl *typealias) { +bool TypeChecker::isPassThroughTypealias(TypeAliasDecl *typealias, + Type underlyingType, + NominalTypeDecl *nominal) { // Pass-through only makes sense when the typealias refers to a nominal // type. - Type underlyingType = typealias->getUnderlyingTypeLoc().getType(); - auto nominal = underlyingType->getAnyNominal(); -======= -/// Determine whether this is a "pass-through" typealias, which has the -/// same type parameters as the nominal type it references and specializes -/// the underlying nominal type with exactly those type parameters. -/// For example, the following typealias \c GX is a pass-through typealias: -/// -/// \code -/// struct X { } -/// typealias GX = X -/// \endcode -/// -/// whereas \c GX2 and \c GX3 are not pass-through because \c GX2 has -/// different type parameters and \c GX3 doesn't pass its type parameters -/// directly through. -/// -/// \code -/// typealias GX2 = X -/// typealias GX3 = X -/// \endcode -static bool isPassThroughTypealias(TypeAliasDecl *typealias, - Type underlyingType, - NominalTypeDecl *nominal) { ->>>>>>> Separate computing interface types and underlying types if (!nominal) return false; // Check that the nominal type and the typealias are either both generic @@ -4410,138 +4274,6 @@ static bool isPassThroughTypealias(TypeAliasDecl *typealias, }); } -<<<<<<< HEAD -======= -/// Form the interface type of an extension from the raw type and the -/// extension's list of generic parameters. -static Type formExtensionInterfaceType( - TypeChecker &tc, ExtensionDecl *ext, - Type type, - GenericParamList *genericParams, - SmallVectorImpl &sameTypeReqs, - bool &mustInferRequirements) { - if (type->is()) - return type; - - // Find the nominal type declaration and its parent type. - if (type->is()) - type = type->getCanonicalType(); - - Type parentType = type->getNominalParent(); - GenericTypeDecl *genericDecl = type->getAnyGeneric(); - - // Reconstruct the parent, if there is one. - if (parentType) { - // Build the nested extension type. - auto parentGenericParams = genericDecl->getGenericParams() - ? genericParams->getOuterParameters() - : genericParams; - parentType = - formExtensionInterfaceType(tc, ext, parentType, parentGenericParams, - sameTypeReqs, mustInferRequirements); - } - - // Find the nominal type. - auto nominal = dyn_cast(genericDecl); - auto typealias = dyn_cast(genericDecl); - if (!nominal) { - Type underlyingType = typealias->getUnderlyingTypeLoc().getType(); - nominal = underlyingType->getNominalOrBoundGenericNominal(); - } - - // Form the result. - Type resultType; - SmallVector genericArgs; - if (!nominal->isGeneric() || isa(nominal)) { - resultType = NominalType::get(nominal, parentType, - nominal->getASTContext()); - } else { - auto currentBoundType = type->getAs(); - - // Form the bound generic type with the type parameters provided. - unsigned gpIndex = 0; - for (auto gp : *genericParams) { - SWIFT_DEFER { ++gpIndex; }; - - auto gpType = gp->getDeclaredInterfaceType(); - genericArgs.push_back(gpType); - - if (currentBoundType) { - sameTypeReqs.emplace_back(RequirementKind::SameType, gpType, - currentBoundType->getGenericArgs()[gpIndex]); - } - } - - resultType = BoundGenericType::get(nominal, parentType, genericArgs); - } - - // If we have a typealias, try to form type sugar. - if (typealias && isPassThroughTypealias(typealias, typealias->getUnderlyingType(), nominal)) { - auto typealiasSig = typealias->getGenericSignature(); - SubstitutionMap subMap; - if (typealiasSig) { - subMap = typealiasSig->getIdentitySubstitutionMap(); - - mustInferRequirements = true; - } - - resultType = TypeAliasType::get(typealias, parentType, subMap, - resultType); - } - - return resultType; -} - -/// Retrieve the generic parameter depth of the extended type. -static unsigned getExtendedTypeGenericDepth(ExtensionDecl *ext) { - auto nominal = ext->getSelfNominalTypeDecl(); - if (!nominal) return static_cast(-1); - - auto sig = nominal->getGenericSignatureOfContext(); - if (!sig) return static_cast(-1); - - return sig->getGenericParams().back()->getDepth(); -} - -/// Check the generic parameters of an extension, recursively handling all of -/// the parameter lists within the extension. -static GenericSignature * -checkExtensionGenericParams(TypeChecker &tc, ExtensionDecl *ext, - GenericParamList *genericParams) { - assert(!ext->getGenericEnvironment()); - - // Form the interface type of the extension. - bool mustInferRequirements = false; - SmallVector sameTypeReqs; - Type extInterfaceType = - formExtensionInterfaceType(tc, ext, ext->getExtendedType(), - genericParams, sameTypeReqs, - mustInferRequirements); - - assert(genericParams && "Missing generic parameters?"); - - auto cannotReuseNominalSignature = [&]() -> bool { - const auto finalDepth = genericParams->getParams().back()->getDepth(); - return mustInferRequirements - || !sameTypeReqs.empty() - || ext->getTrailingWhereClause() - || (getExtendedTypeGenericDepth(ext) != finalDepth); - }; - - // Re-use the signature of the type being extended by default. - if (cannotReuseNominalSignature()) { - return TypeChecker::checkGenericSignature( - genericParams, ext, - /*parent signature*/ nullptr, - /*allowConcreteGenericParams=*/true, - sameTypeReqs, - {TypeLoc{nullptr, extInterfaceType}}); - } - - return ext->getSelfNominalTypeDecl()->getGenericSignatureOfContext(); -} - ->>>>>>> Separate computing interface types and underlying types static bool isNonGenericTypeAliasType(Type type) { // A non-generic typealias can extend a specialized type. if (auto *aliasType = dyn_cast(type.getPointer())) @@ -4574,28 +4306,20 @@ ExtendedTypeRequest::evaluate(Evaluator &eval, ExtensionDecl *ext) const { // Hack to allow extending a generic typealias. if (auto *unboundGeneric = extendedType->getAs()) { if (auto *aliasDecl = dyn_cast(unboundGeneric->getDecl())) { -<<<<<<< HEAD - auto extendedNominal = aliasDecl->getDeclaredInterfaceType()->getAnyNominal(); - if (extendedNominal) - return TypeChecker::isPassThroughTypealias(aliasDecl) - ? extendedType - : extendedNominal->getDeclaredType(); -======= // Nested Hack to break cycles if this is called before validation has // finished. if (aliasDecl->hasInterfaceType()) { auto extendedNominal = aliasDecl->getDeclaredInterfaceType()->getAnyNominal(); if (extendedNominal) - return isPassThroughTypealias(aliasDecl, aliasDecl->getUnderlyingType(), extendedNominal) + return TypeChecker::isPassThroughTypealias(aliasDecl, aliasDecl->getUnderlyingType(), extendedNominal) ? extendedType : extendedNominal->getDeclaredType(); } else { if (auto ty = aliasDecl->getStructuralType()->getAs()) - return isPassThroughTypealias(aliasDecl, ty, ty->getDecl()) + return TypeChecker::isPassThroughTypealias(aliasDecl, ty, ty->getDecl()) ? extendedType : ty->getDecl()->getDeclaredType(); } ->>>>>>> Separate computing interface types and underlying types } } diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index 8c62dc6e985c7..63f9e1b23b5e7 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -525,7 +525,7 @@ static Type formExtensionInterfaceType( auto nominal = dyn_cast(genericDecl); auto typealias = dyn_cast(genericDecl); if (!nominal) { - Type underlyingType = typealias->getUnderlyingTypeLoc().getType(); + Type underlyingType = typealias->getUnderlyingType(); nominal = underlyingType->getNominalOrBoundGenericNominal(); } @@ -556,7 +556,7 @@ static Type formExtensionInterfaceType( } // If we have a typealias, try to form type sugar. - if (typealias && TypeChecker::isPassThroughTypealias(typealias)) { + if (typealias && TypeChecker::isPassThroughTypealias(typealias, typealias->getUnderlyingType(), nominal)) { auto typealiasSig = typealias->getGenericSignature(); SubstitutionMap subMap; if (typealiasSig) { diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp index 587d2644bedb4..401a70db60ca0 100644 --- a/lib/Sema/TypeCheckPattern.cpp +++ b/lib/Sema/TypeCheckPattern.cpp @@ -1497,7 +1497,7 @@ bool TypeChecker::coercePatternToType(Pattern *&P, TypeResolution resolution, } // If there is a subpattern, push the enum element type down onto it. - validateDeclForNameLookup(elt); + validateDecl(elt); if (EEP->hasSubPattern()) { Pattern *sub = EEP->getSubPattern(); if (!elt->hasAssociatedValues()) { diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 7083a84097486..877d6deddd9bc 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -783,9 +783,6 @@ class TypeChecker final : public LazyResolver { void validateDecl(OperatorDecl *decl); void validateDecl(PrecedenceGroupDecl *decl); - /// Perform just enough validation for looking up names using the Decl. - void validateDeclForNameLookup(ValueDecl *D); - /// Validate the given extension declaration, ensuring that it /// properly extends the nominal type it names. void validateExtension(ExtensionDecl *ext); @@ -882,7 +879,9 @@ class TypeChecker final : public LazyResolver { /// typealias GX2 = X /// typealias GX3 = X /// \endcode - static bool isPassThroughTypealias(TypeAliasDecl *typealias); + static bool isPassThroughTypealias(TypeAliasDecl *typealias, + Type underlyingType, + NominalTypeDecl *nominal); /// Determine whether one type is a subtype of another. /// @@ -1011,7 +1010,7 @@ class TypeChecker final : public LazyResolver { void checkDefaultArguments(ParameterList *params, ValueDecl *VD); virtual void resolveDeclSignature(ValueDecl *VD) override { - validateDeclForNameLookup(VD); + validateDecl(VD); } virtual void resolveProtocolEnvironment(ProtocolDecl *proto) override { diff --git a/test/Generics/protocol_type_aliases.swift b/test/Generics/protocol_type_aliases.swift index d922423bf664a..8804caa6cf74c 100644 --- a/test/Generics/protocol_type_aliases.swift +++ b/test/Generics/protocol_type_aliases.swift @@ -42,14 +42,14 @@ func concreteRequirementOnConcreteNestedTypeAlias(_: T) where T: Q2, S = protocol P3 { typealias T = Int } -protocol Q3: P3 { // expected-error{{generic signature requires types 'Int'}} +protocol Q3: P3 { // expected-error{{generic signature requires types 'P3.T' (aka 'Int')}} typealias T = Float } protocol P3_1 { typealias T = Float } -protocol Q3_1: P3, P3_1 {} // expected-error{{generic signature requires types 'Float'}} +protocol Q3_1: P3, P3_1 {} // expected-error{{generic signature requires types 'P3_1.T' (aka 'Float')}} // Subprotocols can force associated types in their parents to be concrete, and diff --git a/test/Generics/requirement_inference.swift b/test/Generics/requirement_inference.swift index 60afcd73d7e59..6f29047e0b100 100644 --- a/test/Generics/requirement_inference.swift +++ b/test/Generics/requirement_inference.swift @@ -383,7 +383,7 @@ struct X28 : P2 { } // CHECK-LABEL: .P28@ -// CHECK-NEXT: Requirement signature: +// CHECK-NEXT: Requirement signature: // CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : P3, τ_0_0.P3Assoc == X28> protocol P28: P3 { typealias P3Assoc = X28 // expected-warning{{typealias overriding associated type}} diff --git a/tools/swift-api-digester/ModuleAnalyzerNodes.cpp b/tools/swift-api-digester/ModuleAnalyzerNodes.cpp index 23747b6932ee0..d5adcfff0db0e 100644 --- a/tools/swift-api-digester/ModuleAnalyzerNodes.cpp +++ b/tools/swift-api-digester/ModuleAnalyzerNodes.cpp @@ -1679,7 +1679,7 @@ SwiftDeclCollector::constructVarNode(ValueDecl *VD) { SDKNode *swift::ide::api:: SwiftDeclCollector::constructTypeAliasNode(TypeAliasDecl *TAD) { auto Alias = SDKNodeInitInfo(Ctx, TAD).createSDKNode(SDKNodeKind::DeclTypeAlias); - Alias->addChild(constructTypeNode(TAD->getUnderlyingTypeLoc().getType())); + Alias->addChild(constructTypeNode(TAD->getUnderlyingType())); return Alias; } diff --git a/tools/swift-ide-test/ModuleAPIDiff.cpp b/tools/swift-ide-test/ModuleAPIDiff.cpp index dbca719460436..b3a54a75c0ca8 100644 --- a/tools/swift-ide-test/ModuleAPIDiff.cpp +++ b/tools/swift-ide-test/ModuleAPIDiff.cpp @@ -833,7 +833,7 @@ class SMAModelGenerator : public DeclVisitor { void visitTypeAliasDecl(TypeAliasDecl *TAD) { auto ResultTD = std::make_shared(); ResultTD->Name = convertToIdentifier(TAD->getName()); - ResultTD->Type = convertToTypeName(TAD->getUnderlyingTypeLoc().getType()); + ResultTD->Type = convertToTypeName(TAD->getUnderlyingType()); // FIXME // ResultTD->Attributes = ?; Result.Typealiases.emplace_back(std::move(ResultTD)); diff --git a/validation-test/compiler_crashers_2_fixed/0145-sr7097.swift b/validation-test/compiler_crashers_2_fixed/0145-sr7097.swift index bc369c7f47a02..2e6adfc824840 100644 --- a/validation-test/compiler_crashers_2_fixed/0145-sr7097.swift +++ b/validation-test/compiler_crashers_2_fixed/0145-sr7097.swift @@ -9,7 +9,7 @@ protocol P2 { } // CHECK-LABEL: .P3@ -// CHECK-NEXT: Requirement signature: +// CHECK-NEXT: Requirement signature: protocol P3 : P2 { } struct S0 where M.Assoc: P1 { } // expected-warning{{redundant conformance constraint 'M.Assoc': 'P1'}} From c254f4d2f83b8c1b43f3b78366aa420c35ca0cf6 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 13 Sep 2019 15:48:24 -0700 Subject: [PATCH 046/199] Setting the underlying type should set the structural type too This avoids making the structural type dependent on whether the interface type has been computed and neatly avoids special-casing non-parsed declarations which set their underlying type up front. --- lib/AST/ASTPrinter.cpp | 2 +- lib/AST/Decl.cpp | 7 +++++++ lib/AST/GenericSignatureBuilder.cpp | 2 -- lib/AST/TypeCheckRequests.cpp | 4 ---- lib/Sema/TypeCheckDecl.cpp | 6 +++--- lib/Sema/TypeCheckGeneric.cpp | 9 +-------- 6 files changed, 12 insertions(+), 18 deletions(-) diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 29d9e2cbcc7c2..fce8f8825ec7e 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -2294,7 +2294,7 @@ void PrintAST::visitTypeAliasDecl(TypeAliasDecl *decl) { // preserving sugar. llvm::SaveAndRestore setGenericEnv(Options.GenericEnv, decl->getGenericEnvironment()); - printTypeLoc(TypeLoc::withoutLoc(Ty)); + printTypeLoc(TypeLoc(decl->getUnderlyingTypeRepr(), Ty)); printGenericDeclGenericRequirements(decl); } } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 4f4017861bab0..c08cf42ad8cb5 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -3553,6 +3553,13 @@ Type TypeAliasDecl::getUnderlyingType() const { } void TypeAliasDecl::setUnderlyingType(Type underlying) { + // lldb creates global typealiases containing archetypes + // sometimes... + if (underlying->hasArchetype() && isGenericContext()) + underlying = underlying->mapTypeOutOfContext(); + getASTContext().evaluator.cacheOutput( + StructuralTypeRequest{const_cast(this)}, + std::move(underlying)); getASTContext().evaluator.cacheOutput( UnderlyingTypeRequest{const_cast(this)}, std::move(underlying)); diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp index 0adec2fd06a28..1aedddaa59276 100644 --- a/lib/AST/GenericSignatureBuilder.cpp +++ b/lib/AST/GenericSignatureBuilder.cpp @@ -3785,8 +3785,6 @@ PotentialArchetype *GenericSignatureBuilder::realizePotentialArchetype( static Type getStructuralType(TypeDecl *typeDecl) { if (auto typealias = dyn_cast(typeDecl)) { - if (typealias->hasInterfaceType()) - return typealias->getDeclaredInterfaceType(); return typealias->getStructuralType(); } diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index 94aab51ab3ced..2a1cab27fabb7 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -837,9 +837,5 @@ UnderlyingTypeRequest::getCachedResult() const { void UnderlyingTypeRequest::cacheResult(Type value) const { auto *typeAlias = std::get<0>(getStorage()); - // lldb creates global typealiases containing archetypes - // sometimes... - if (value->hasArchetype() && typeAlias->isGenericContext()) - value = value->mapTypeOutOfContext(); typeAlias->UnderlyingTy.setType(value); } diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index b03b334b477a6..8c9a57aba2046 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -3492,14 +3492,14 @@ UnderlyingTypeRequest::evaluate(Evaluator &evaluator, return ErrorType::get(typeAlias->getASTContext()); } - if (TypeChecker::validateType(typeAlias->getASTContext(), - typeAlias->getUnderlyingTypeLoc(), + auto underlyingLoc = TypeLoc(typeAlias->getUnderlyingTypeRepr()); + if (TypeChecker::validateType(typeAlias->getASTContext(), underlyingLoc, TypeResolution::forInterface(typeAlias), options)) { typeAlias->setInvalid(); return ErrorType::get(typeAlias->getASTContext()); } - return ty; + return underlyingLoc.getType(); } /// Bind the given function declaration, which declares an operator, to the corresponding operator declaration. diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index 63f9e1b23b5e7..eacb07beca341 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -966,14 +966,7 @@ RequirementRequest::evaluate(Evaluator &evaluator, llvm::Expected StructuralTypeRequest::evaluate(Evaluator &evaluator, - TypeAliasDecl *typeAlias) const { - // Fast path: If the interface type is already resolved, there's no need - // to compute the structural type. This also prevents us from writing - // ErrorTypes into otherwise valid ASTs with generated typealiases. - if (typeAlias->hasInterfaceType()) { - return typeAlias->getInterfaceType()->getMetatypeInstanceType(); - } - + TypeAliasDecl *typeAlias) const { TypeResolutionOptions options((typeAlias->getGenericParams() ? TypeResolverContext::GenericTypeAliasDecl : TypeResolverContext::TypeAliasDecl)); From 94265e81634ae2f4cedccec67779c09ae14b0851 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Tue, 17 Sep 2019 09:05:23 -0700 Subject: [PATCH 047/199] [Frontend] Add a comment about 9e6d4db (#27169) With wording help from David U. --- lib/FrontendTool/FrontendTool.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 8c846c863526c..fc23df524dd20 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -1122,6 +1122,14 @@ static bool performCompile(CompilerInstance &Instance, if (Action == FrontendOptions::ActionType::Typecheck) { if (emitIndexData(Invocation, Instance)) return true; + // FIXME: Whole-module outputs with a non-whole-module -typecheck ought to + // be disallowed, but the driver implements -index-file mode by generating a + // regular whole-module frontend command line and modifying it to index just + // one file (by making it a primary) instead of all of them. If that + // invocation also has flags to emit whole-module supplementary outputs, the + // compiler can crash trying to access information for non-type-checked + // declarations in the non-primary files. For now, prevent those crashes by + // guarding the emission of whole-module supplementary outputs. if (opts.InputsAndOutputs.isWholeModule()) { if (emitAnyWholeModulePostTypeCheckSupplementaryOutputs(Instance, Invocation, From 2a7e0099d24a1d318cb5abf8e4409f1a186e398c Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Tue, 17 Sep 2019 09:08:31 -0700 Subject: [PATCH 048/199] [Diagnostics] Add notes for the type_cannot_conform error that point to the declaration that requires protocol conformance. --- include/swift/AST/DiagnosticsSema.def | 9 ++++ lib/Sema/CSDiagnostics.cpp | 49 ++++++++++++++++--- lib/Sema/CSDiagnostics.h | 8 +-- test/Constraints/diagnostics.swift | 4 ++ test/Constraints/function_builder_diags.swift | 2 +- test/Constraints/generics.swift | 1 + test/Constraints/operator.swift | 1 + .../conditional_conformances_literals.swift | 1 + test/Generics/existential_restrictions.swift | 4 ++ .../conforms/error_self_conformance.swift | 3 ++ test/type/opaque.swift | 5 +- test/type/subclass_composition.swift | 1 + .../rdar27830834.swift | 4 +- .../0196-rdar48937223.swift | 1 + ...set-llvm-attributesetnode-nodeequals.swift | 5 +- 15 files changed, 82 insertions(+), 16 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 7f37e16bb2efc..48d4d18ec6a5f 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1664,6 +1664,15 @@ ERROR(type_cannot_conform, none, "%select{|protocol }0type %1 cannot conform to %2; " "only struct/enum/class types can conform to protocols", (bool, Type, Type)) +NOTE(required_by_opaque_return,none, + "required by opaque return type of %0 %1", (DescriptiveDeclKind, DeclName)) +NOTE(required_by_decl,none, + "required by %0 %1 where %2 = %3", + (DescriptiveDeclKind, DeclName, Type, Type)) +NOTE(required_by_decl_ref,none, + "required by referencing %0 %1 on %2 where %3 = %4", + (DescriptiveDeclKind, DeclName, Type, Type, Type)) + ERROR(protocol_does_not_conform_static,none, "%0 cannot be used as a type conforming to protocol %1 because %1 " "has static requirements", diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 8582a5a21620b..8bda09f86cfcc 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -597,17 +597,54 @@ bool MissingConformanceFailure::diagnoseAsError() { bool MissingConformanceFailure::diagnoseTypeCannotConform(Expr *anchor, Type nonConformingType, Type protocolType) const { - if (nonConformingType->is() || + if (!(nonConformingType->is() || nonConformingType->is() || nonConformingType->isExistentialType() || - nonConformingType->is()) { - emitDiagnostic(anchor->getLoc(), diag::type_cannot_conform, - nonConformingType->isExistentialType(), nonConformingType, - protocolType); + nonConformingType->is())) { + return false; + } + + emitDiagnostic(anchor->getLoc(), diag::type_cannot_conform, + nonConformingType->isExistentialType(), nonConformingType, + protocolType); + + if (auto *OTD = dyn_cast(AffectedDecl)) { + auto *namingDecl = OTD->getNamingDecl(); + if (auto *repr = namingDecl->getOpaqueResultTypeRepr()) { + emitDiagnostic(repr->getLoc(), diag::required_by_opaque_return, + namingDecl->getDescriptiveKind(), namingDecl->getFullName()) + .highlight(repr->getSourceRange()); + } return true; } - return false; + auto &req = getRequirement(); + auto *reqDC = getRequirementDC(); + auto *genericCtx = getGenericContext(); + auto noteLocation = reqDC->getAsDecl()->getLoc(); + + if (!noteLocation.isValid()) + noteLocation = anchor->getLoc(); + + if (isConditional()) { + emitDiagnostic(noteLocation, diag::requirement_implied_by_conditional_conformance, + resolveType(Conformance->getType()), + Conformance->getProtocol()->getDeclaredInterfaceType()); + } else if (genericCtx != reqDC && (genericCtx->isChildContextOf(reqDC) || + isStaticOrInstanceMember(AffectedDecl))) { + emitDiagnostic(noteLocation, diag::required_by_decl_ref, + AffectedDecl->getDescriptiveKind(), + AffectedDecl->getFullName(), + reqDC->getSelfNominalTypeDecl()->getDeclaredType(), + req.getFirstType(), nonConformingType); + } else { + emitDiagnostic(noteLocation, diag::required_by_decl, + AffectedDecl->getDescriptiveKind(), + AffectedDecl->getFullName(), req.getFirstType(), + nonConformingType); + } + + return true; } Optional> GenericArgumentsMismatchFailure::getDiagnosticFor( diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index db294900e72ab..cd3208cbd41cd 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -308,6 +308,10 @@ class RequirementFailure : public FailureDiagnostic { isa(apply); } + /// Determine whether given declaration represents a static + /// or instance property/method, excluding operators. + static bool isStaticOrInstanceMember(const ValueDecl *decl); + private: /// Retrieve declaration associated with failing generic requirement. ValueDecl *getDeclRef() const; @@ -317,10 +321,6 @@ class RequirementFailure : public FailureDiagnostic { void emitRequirementNote(const Decl *anchor, Type lhs, Type rhs) const; - /// Determine whether given declaration represents a static - /// or instance property/method, excluding operators. - static bool isStaticOrInstanceMember(const ValueDecl *decl); - /// If this is a failure in conditional requirement, retrieve /// conformance information. ProtocolConformance * diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index 8f6fce9033deb..073c10dc32d3d 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -28,6 +28,9 @@ func f3(_: @escaping (_: @escaping (Int) -> Float) -> Int) {} func f4(_ x: Int) -> Int { } func f5(_ : T) { } +// expected-note@-1 {{required by global function 'f5' where 'T' = '(Int) -> Int'}} +// expected-note@-2 {{required by global function 'f5' where 'T' = '(Int, String)'}} +// expected-note@-3 {{required by global function 'f5' where 'T' = 'Int.Type'}} func f6(_ t: T, _ u: U) where T.SomeType == U.SomeType {} @@ -96,6 +99,7 @@ func f7() -> (c: Int, v: A) { } func f8(_ n: T, _ f: @escaping (T) -> T) {} +// expected-note@-1 {{required by global function 'f8' where 'T' = 'Tup' (aka '(Int, Double)')}} f8(3, f4) // expected-error {{argument type 'Int' does not conform to expected type 'P2'}} typealias Tup = (Int, Double) func f9(_ x: Tup) -> Tup { return x } diff --git a/test/Constraints/function_builder_diags.swift b/test/Constraints/function_builder_diags.swift index 95c96d566c636..d7de38e317334 100644 --- a/test/Constraints/function_builder_diags.swift +++ b/test/Constraints/function_builder_diags.swift @@ -144,7 +144,7 @@ struct TupleP : P { @_functionBuilder struct Builder { - static func buildBlock(_ stmt1: S0, _ stmt2: S1) + static func buildBlock(_ stmt1: S0, _ stmt2: S1) // expected-note {{required by static method 'buildBlock' where 'S1' = 'Label.Type'}} -> TupleP<(S0, S1)> where S0: P, S1: P { return TupleP((stmt1, stmt2)) } diff --git a/test/Constraints/generics.swift b/test/Constraints/generics.swift index b75400ed550ba..20c5de44002c3 100644 --- a/test/Constraints/generics.swift +++ b/test/Constraints/generics.swift @@ -192,6 +192,7 @@ func r22459135() { // QoI: Friendlier error message for "[] as Set" // QoI: "argument for generic parameter 'Element' could not be inferred" lacks context _ = [] as Set // expected-error {{protocol type 'Any' cannot conform to 'Hashable'; only struct/enum/class types can conform to protocols}} +// expected-note@-1 {{required by generic struct 'Set' where 'Element' = 'Any'}} // QoI: Error when unable to infer generic archetype lacks greatness diff --git a/test/Constraints/operator.swift b/test/Constraints/operator.swift index b84b827205f65..e1aaa30af4a40 100644 --- a/test/Constraints/operator.swift +++ b/test/Constraints/operator.swift @@ -221,6 +221,7 @@ func rdar46459603() { // expected-note@-2 {{expected an argument list of type '(Self, Self)'}} _ = [arr.values] == [[e]] // expected-error@-1 {{protocol type 'Any' cannot conform to 'Equatable'; only struct/enum/class types can conform to protocols}} + // expected-note@-2 {{requirement from conditional conformance of '[Any]' to 'Equatable'}} } // SR-10843 diff --git a/test/Generics/conditional_conformances_literals.swift b/test/Generics/conditional_conformances_literals.swift index a59fba4550f54..f16147a6bce07 100644 --- a/test/Generics/conditional_conformances_literals.swift +++ b/test/Generics/conditional_conformances_literals.swift @@ -16,6 +16,7 @@ extension Array: Conforms where Element: Conforms {} // expected-note@-1 5 {{requirement from conditional conformance of '[Fails]' to 'Conforms'}} extension Dictionary: Conforms where Value: Conforms {} // expected-note@-1 3 {{requirement from conditional conformance of '[Int : Fails]' to 'Conforms'}} +// expected-note@-2 2 {{requirement from conditional conformance of '[Int : Conforms]' to 'Conforms'}} let works = Works() let fails = Fails() diff --git a/test/Generics/existential_restrictions.swift b/test/Generics/existential_restrictions.swift index c2ce683f69d24..613d62fed584d 100644 --- a/test/Generics/existential_restrictions.swift +++ b/test/Generics/existential_restrictions.swift @@ -9,7 +9,10 @@ protocol CP : class { } } func fP(_ t: T) { } +// expected-note@-1 {{required by global function 'fP' where 'T' = 'P'}} +// expected-note@-2 {{required by global function 'fP' where 'T' = 'OP & P'}} func fOP(_ t: T) { } +// expected-note@-1 {{required by global function 'fOP' where 'T' = 'OP & P'}} func fOPE(_ t: OP) { } func fSP(_ t: T) { } func fAO(_ t: T) { } @@ -73,6 +76,7 @@ protocol Mine {} class M1: Mine {} class M2: Mine {} extension Collection where Iterator.Element : Mine { +// expected-note@-1 {{required by referencing instance method 'takeAll()' on 'Collection'}} func takeAll() {} } diff --git a/test/decl/protocol/conforms/error_self_conformance.swift b/test/decl/protocol/conforms/error_self_conformance.swift index e1b2bcd68ed78..67db0981205fc 100644 --- a/test/decl/protocol/conforms/error_self_conformance.swift +++ b/test/decl/protocol/conforms/error_self_conformance.swift @@ -1,6 +1,9 @@ // RUN: %target-typecheck-verify-swift func wantsError(_: T) {} +// expected-note@-1 {{required by global function 'wantsError' where 'T' = 'ErrorRefinement'}} +// expected-note@-2 {{required by global function 'wantsError' where 'T' = 'Error & OtherProtocol'}} +// expected-note@-3 {{required by global function 'wantsError' where 'T' = 'C & Error'}} func testSimple(error: Error) { wantsError(error) diff --git a/test/type/opaque.swift b/test/type/opaque.swift index 15d69f70225e1..8ae8edb52f9f2 100644 --- a/test/type/opaque.swift +++ b/test/type/opaque.swift @@ -376,8 +376,9 @@ protocol P_51641323 { func rdar_51641323() { struct Foo: P_51641323 { - var foo: some P_51641323 { {} } - // expected-error@-1 {{type '() -> ()' cannot conform to 'P_51641323'; only struct/enum/class types can conform to protocols}} + var foo: some P_51641323 { // expected-note {{required by opaque return type of property 'foo'}} + {} // expected-error {{type '() -> ()' cannot conform to 'P_51641323'; only struct/enum/class types can conform to protocols}} + } } } diff --git a/test/type/subclass_composition.swift b/test/type/subclass_composition.swift index 7fc6d48d6577d..2c0a618a78c97 100644 --- a/test/type/subclass_composition.swift +++ b/test/type/subclass_composition.swift @@ -300,6 +300,7 @@ func dependentMemberTypes( func conformsToAnyObject(_: T) {} func conformsToP1(_: T) {} +// expected-note@-1 {{required by global function 'conformsToP1' where 'T' = 'P1'}} func conformsToP2(_: T) {} func conformsToBaseIntAndP2 & P2>(_: T) {} // expected-note@-1 {{where 'T' = 'FakeDerived'}} diff --git a/validation-test/Sema/type_checker_crashers_fixed/rdar27830834.swift b/validation-test/Sema/type_checker_crashers_fixed/rdar27830834.swift index 9776ec796afe3..1bf2e92ddc8be 100644 --- a/validation-test/Sema/type_checker_crashers_fixed/rdar27830834.swift +++ b/validation-test/Sema/type_checker_crashers_fixed/rdar27830834.swift @@ -1,4 +1,6 @@ // RUN: %target-swift-frontend %s -typecheck -verify var d = [String:String]() -_ = "\(d.map{ [$0 : $0] })" // expected-error {{type '(key: String, value: String)' cannot conform to 'Hashable'; only struct/enum/class types can conform to protocols}} +_ = "\(d.map{ [$0 : $0] })" +// expected-error@-1 {{type '(key: String, value: String)' cannot conform to 'Hashable'; only struct/enum/class types can conform to protocols}} +// expected-note@-2 {{required by generic struct 'Dictionary' where 'Key' = '(key: String, value: String)'}} diff --git a/validation-test/compiler_crashers_2_fixed/0196-rdar48937223.swift b/validation-test/compiler_crashers_2_fixed/0196-rdar48937223.swift index 2abfc949c9d98..c8e9979569714 100644 --- a/validation-test/compiler_crashers_2_fixed/0196-rdar48937223.swift +++ b/validation-test/compiler_crashers_2_fixed/0196-rdar48937223.swift @@ -3,6 +3,7 @@ protocol P {} func fn(_ arg1: T, arg2: (T) -> U) {} +// expected-note@-1 {{required by global function 'fn(_:arg2:)' where 'U' = '()'}} func test(str: String) { fn(str) { arg in // expected-error {{type '()' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} diff --git a/validation-test/compiler_crashers_fixed/00017-llvm-foldingset-llvm-attributesetnode-nodeequals.swift b/validation-test/compiler_crashers_fixed/00017-llvm-foldingset-llvm-attributesetnode-nodeequals.swift index 371cf90e94a2d..aae9af5957647 100644 --- a/validation-test/compiler_crashers_fixed/00017-llvm-foldingset-llvm-attributesetnode-nodeequals.swift +++ b/validation-test/compiler_crashers_fixed/00017-llvm-foldingset-llvm-attributesetnode-nodeequals.swift @@ -17,6 +17,7 @@ protocol BooleanProtocol { extension Bool : BooleanProtocol { var boolValue: Bool { return self } } -func f(_ b: T) { -} +func f(_ b: T) {} +// expected-note@-1 {{required by global function 'f' where 'T' = 'BooleanProtocol'}} + f(true as BooleanProtocol) // expected-error {{protocol type 'BooleanProtocol' cannot conform to 'BooleanProtocol'; only struct/enum/class types can conform to protocols}} From 4d02463e2b2a361b532d2d45af4a5c1a2d47cdc7 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 17 Sep 2019 10:31:04 -0700 Subject: [PATCH 049/199] [Diagnostics] Fix `missing argument` diagnostic to support closures with captures --- lib/Sema/CSDiagnostics.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 8c68c66e0d6f6..a5427958b73ea 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -3504,7 +3504,11 @@ bool MissingArgumentsFailure::diagnoseAsError() { path.back().getKind() == ConstraintLocator::ContextualType)) return false; - if (auto *closure = dyn_cast(getAnchor())) + auto *anchor = getAnchor(); + if (auto *captureList = dyn_cast(anchor)) + anchor = captureList->getClosureBody(); + + if (auto *closure = dyn_cast(anchor)) return diagnoseTrailingClosure(closure); return false; From 0aeaf7f15e7b18c346d026fa7535c5134b768d4c Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 17 Sep 2019 10:34:40 -0700 Subject: [PATCH 050/199] [Diagnostics] NFC: Remove "trailing" from method name for closures with missing args `MissingArgumentsFailure::diagnoseClosure` can actually diagnose both closures in argument positions as well as when their type comes from context e.g. `let _: (Int) -> Void = {}`. --- lib/Sema/CSDiagnostics.cpp | 4 ++-- lib/Sema/CSDiagnostics.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index a5427958b73ea..aecf9c527c5e2 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -3509,12 +3509,12 @@ bool MissingArgumentsFailure::diagnoseAsError() { anchor = captureList->getClosureBody(); if (auto *closure = dyn_cast(anchor)) - return diagnoseTrailingClosure(closure); + return diagnoseClosure(closure); return false; } -bool MissingArgumentsFailure::diagnoseTrailingClosure(ClosureExpr *closure) { +bool MissingArgumentsFailure::diagnoseClosure(ClosureExpr *closure) { auto &cs = getConstraintSystem(); FunctionType *funcType = nullptr; diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 49ec8dcb50416..977981773da45 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -1192,9 +1192,9 @@ class MissingArgumentsFailure final : public FailureDiagnostic { bool diagnoseAsError() override; private: - /// If missing arguments come from trailing closure, + /// If missing arguments come from a closure, /// let's produce tailored diagnostics. - bool diagnoseTrailingClosure(ClosureExpr *closure); + bool diagnoseClosure(ClosureExpr *closure); }; class OutOfOrderArgumentFailure final : public FailureDiagnostic { From d9c8ae4ce85ac04369d14fa67dc3f56efdd62ef1 Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Tue, 17 Sep 2019 18:38:01 +0100 Subject: [PATCH 051/199] [AST] Remove isTypeContext() check from hasValueSemantics() and move the responsibility to the caller --- lib/AST/Decl.cpp | 3 ++- lib/AST/DeclContext.cpp | 3 --- lib/Sema/TypeCheckDecl.cpp | 8 ++++++-- lib/Sema/TypeCheckStorage.cpp | 12 +++++++----- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index fc9d1b1dd78a8..7a60a6acdf9fc 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -5708,8 +5708,9 @@ void VarDecl::emitLetToVarNoteIfSimple(DeclContext *UseDC) const { if (AD->isGetter() && !AD->getAccessorKeywordLoc().isValid()) return; + auto accessorDC = AD->getDeclContext(); // Do not suggest the fix-it if `Self` is a class type. - if (!AD->getDeclContext()->hasValueSemantics()) { + if (accessorDC->isTypeContext() && !accessorDC->hasValueSemantics()) { return; } } diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index ff0fe6f528949..e70e7ebf088e3 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -1025,9 +1025,6 @@ DeclContextKind DeclContext::getContextKind() const { } bool DeclContext::hasValueSemantics() const { - if (!isTypeContext()) - return false; - if (auto contextTy = getSelfTypeInContext()) { return !contextTy->hasReferenceSemantics(); } diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 8c578ca5316bb..8de2d9912884c 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -1959,7 +1959,9 @@ void TypeChecker::validateDecl(OperatorDecl *OD) { llvm::Expected SelfAccessKindRequest::evaluate(Evaluator &evaluator, FuncDecl *FD) const { if (FD->getAttrs().getAttribute(true)) { - if (!FD->isInstanceMember() || !FD->getDeclContext()->hasValueSemantics()) { + auto functionDC = FD->getDeclContext(); + if (!FD->isInstanceMember() || + (functionDC->isTypeContext() && !functionDC->hasValueSemantics())) { return SelfAccessKind::NonMutating; } return SelfAccessKind::Mutating; @@ -1981,7 +1983,9 @@ SelfAccessKindRequest::evaluate(Evaluator &evaluator, FuncDecl *FD) const { case AccessorKind::MutableAddress: case AccessorKind::Set: case AccessorKind::Modify: - if (AD->isInstanceMember() && AD->getDeclContext()->hasValueSemantics()) + auto accessorDC = AD->getDeclContext(); + if (AD->isInstanceMember() && accessorDC->isTypeContext() && + accessorDC->hasValueSemantics()) return SelfAccessKind::Mutating; break; diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index 95c2b8428e208..7421d25e59961 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -268,8 +268,9 @@ void swift::validatePatternBindingEntries(TypeChecker &tc, llvm::Expected IsGetterMutatingRequest::evaluate(Evaluator &evaluator, AbstractStorageDecl *storage) const { - bool result = - (!storage->isStatic() && storage->getDeclContext()->hasValueSemantics()); + auto storageDC = storage->getDeclContext(); + bool result = (!storage->isStatic() && storageDC->isTypeContext() && + storageDC->hasValueSemantics()); // 'lazy' overrides the normal accessor-based rules and heavily // restricts what accessors can be used. The getter is considered @@ -297,7 +298,7 @@ IsGetterMutatingRequest::evaluate(Evaluator &evaluator, // Protocol requirements are always written as '{ get }' or '{ get set }'; // the @_borrowed attribute determines if getReadImpl() becomes Get or Read. - if (isa(storage->getDeclContext())) + if (isa(storageDC)) return checkMutability(AccessorKind::Get); switch (storage->getReadImpl()) { @@ -323,8 +324,9 @@ IsSetterMutatingRequest::evaluate(Evaluator &evaluator, AbstractStorageDecl *storage) const { // By default, the setter is mutating if we have an instance member of a // value type, but this can be overridden below. - bool result = - (!storage->isStatic() && storage->getDeclContext()->hasValueSemantics()); + auto storageDC = storage->getDeclContext(); + bool result = (!storage->isStatic() && storageDC->isTypeContext() && + storageDC->hasValueSemantics()); // If we have an attached property wrapper, the setter is mutating // or not based on the composition of the wrappers. From 039f67be14b837fdd8f9b22a7b4184dbeb5a48f7 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Tue, 17 Sep 2019 11:40:38 -0700 Subject: [PATCH 052/199] utils: bump to CMake 3.15.1 CMake 3.15.3 is the current stable release. Update to 3.15.1 as CMake usually has bug fixes in the first release. --- utils/update_checkout/update-checkout-config.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/utils/update_checkout/update-checkout-config.json b/utils/update_checkout/update-checkout-config.json index 488e8713ef4ab..e5ff863533603 100644 --- a/utils/update_checkout/update-checkout-config.json +++ b/utils/update_checkout/update-checkout-config.json @@ -77,7 +77,7 @@ "swift-xcode-playground-support": "master", "ninja": "release", "icu": "release-61-1", - "cmake": "v3.15.0", + "cmake": "v3.15.1", "clang-tools-extra": "stable", "libcxx": "stable", "indexstore-db": "master", @@ -102,7 +102,7 @@ "swift-xcode-playground-support": "master", "ninja": "release", "icu": "release-61-1", - "cmake": "v3.15.0", + "cmake": "v3.15.1", "indexstore-db": "master", "sourcekit-lsp": "master" } @@ -129,7 +129,7 @@ "swift-xcode-playground-support": "master", "ninja": "release", "icu": "release-61-1", - "cmake": "v3.15.0", + "cmake": "v3.15.1", "clang-tools-extra": "upstream-with-swift", "libcxx": "upstream-with-swift", "indexstore-db": "master", @@ -153,7 +153,7 @@ "swift-xcode-playground-support": "master", "ninja": "release", "icu": "release-61-1", - "cmake": "v3.15.0", + "cmake": "v3.15.1", "indexstore-db": "master", "sourcekit-lsp": "master" } @@ -425,7 +425,7 @@ "swift-xcode-playground-support": "master", "ninja": "release", "icu": "release-61-1", - "cmake": "v3.15.0", + "cmake": "v3.15.1", "clang-tools-extra": "apple/stable/20190619", "libcxx": "apple/stable/20190619", "indexstore-db": "master", From 7687293b7b36e2b90e595354c8407305085427b8 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Tue, 17 Sep 2019 11:04:21 -0700 Subject: [PATCH 053/199] [Diagnostics] Adjust the description of existential types for the type_cannot_conform diagnostic message. --- include/swift/AST/DiagnosticsSema.def | 2 +- test/Constraints/generics.swift | 2 +- test/Constraints/operator.swift | 2 +- .../Generics/conditional_conformances_literals.swift | 4 ++-- test/Generics/existential_restrictions.swift | 12 ++++++------ .../protocol/conforms/error_self_conformance.swift | 6 +++--- test/stmt/foreach.swift | 2 +- test/type/subclass_composition.swift | 2 +- ...foldingset-llvm-attributesetnode-nodeequals.swift | 2 +- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 48d4d18ec6a5f..d0223c58d21cc 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1661,7 +1661,7 @@ ERROR(use_of_equal_instead_of_equality,none, "use of '=' in a boolean context, did you mean '=='?", ()) ERROR(type_cannot_conform, none, - "%select{|protocol }0type %1 cannot conform to %2; " + "%select{|value of protocol }0type %1 cannot conform to %2; " "only struct/enum/class types can conform to protocols", (bool, Type, Type)) NOTE(required_by_opaque_return,none, diff --git a/test/Constraints/generics.swift b/test/Constraints/generics.swift index 20c5de44002c3..582a5eb6fb54c 100644 --- a/test/Constraints/generics.swift +++ b/test/Constraints/generics.swift @@ -191,7 +191,7 @@ func r22459135() { // QoI: Friendlier error message for "[] as Set" // QoI: "argument for generic parameter 'Element' could not be inferred" lacks context -_ = [] as Set // expected-error {{protocol type 'Any' cannot conform to 'Hashable'; only struct/enum/class types can conform to protocols}} +_ = [] as Set // expected-error {{value of protocol type 'Any' cannot conform to 'Hashable'; only struct/enum/class types can conform to protocols}} // expected-note@-1 {{required by generic struct 'Set' where 'Element' = 'Any'}} diff --git a/test/Constraints/operator.swift b/test/Constraints/operator.swift index e1aaa30af4a40..14cdeb624d2e2 100644 --- a/test/Constraints/operator.swift +++ b/test/Constraints/operator.swift @@ -220,7 +220,7 @@ func rdar46459603() { // expected-error@-1 {{binary operator '==' cannot be applied to operands of type 'Dictionary.Values' and '[E]'}} // expected-note@-2 {{expected an argument list of type '(Self, Self)'}} _ = [arr.values] == [[e]] - // expected-error@-1 {{protocol type 'Any' cannot conform to 'Equatable'; only struct/enum/class types can conform to protocols}} + // expected-error@-1 {{value of protocol type 'Any' cannot conform to 'Equatable'; only struct/enum/class types can conform to protocols}} // expected-note@-2 {{requirement from conditional conformance of '[Any]' to 'Equatable'}} } diff --git a/test/Generics/conditional_conformances_literals.swift b/test/Generics/conditional_conformances_literals.swift index f16147a6bce07..f722b89c3ae56 100644 --- a/test/Generics/conditional_conformances_literals.swift +++ b/test/Generics/conditional_conformances_literals.swift @@ -128,9 +128,9 @@ func combined() { // Needs self conforming protocols: let _: Conforms = [[0: [1 : [works]] as Conforms]] - // expected-error@-1 {{protocol type 'Conforms' cannot conform to 'Conforms'; only struct/enum/class types can conform to protocols}} + // expected-error@-1 {{value of protocol type 'Conforms' cannot conform to 'Conforms'; only struct/enum/class types can conform to protocols}} let _: Conforms = [[0: [1 : [fails]] as Conforms]] // expected-error@-1 {{protocol 'Conforms' requires that 'Fails' conform to 'Conforms'}} - // expected-error@-2 {{protocol type 'Conforms' cannot conform to 'Conforms'; only struct/enum/class types can conform to protocols}} + // expected-error@-2 {{value of protocol type 'Conforms' cannot conform to 'Conforms'; only struct/enum/class types can conform to protocols}} } diff --git a/test/Generics/existential_restrictions.swift b/test/Generics/existential_restrictions.swift index 613d62fed584d..8f1d2e459dabc 100644 --- a/test/Generics/existential_restrictions.swift +++ b/test/Generics/existential_restrictions.swift @@ -20,7 +20,7 @@ func fAOE(_ t: AnyObject) { } func fT(_ t: T) { } func testPassExistential(_ p: P, op: OP, opp: OP & P, cp: CP, sp: SP, any: Any, ao: AnyObject) { - fP(p) // expected-error{{protocol type 'P' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} + fP(p) // expected-error{{value of protocol type 'P' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} fAO(p) // expected-error{{cannot invoke 'fAO' with an argument list of type '(P)'}} // expected-note{{expected an argument list of type '(T)'}} fAOE(p) // expected-error{{argument type 'P' does not conform to expected type 'AnyObject'}} fT(p) @@ -34,8 +34,8 @@ func testPassExistential(_ p: P, op: OP, opp: OP & P, cp: CP, sp: SP, any: Any, fAOE(cp) fT(cp) - fP(opp) // expected-error{{protocol type 'OP & P' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} - fOP(opp) // expected-error{{protocol type 'OP & P' cannot conform to 'OP'; only struct/enum/class types can conform to protocols}} + fP(opp) // expected-error{{value of protocol type 'OP & P' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} + fOP(opp) // expected-error{{value of protocol type 'OP & P' cannot conform to 'OP'; only struct/enum/class types can conform to protocols}} fAO(opp) // expected-error{{cannot invoke 'fAO' with an argument list of type '(OP & P)'}} // expected-note{{expected an argument list of type '(T)'}} fAOE(opp) fT(opp) @@ -61,9 +61,9 @@ class GAO {} // expected-note 2{{requirement specified as 'T' : ' func blackHole(_ t: Any) {} func testBindExistential() { - blackHole(GP

()) // expected-error{{protocol type 'P' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} + blackHole(GP

()) // expected-error{{value of protocol type 'P' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} blackHole(GOP()) - blackHole(GCP()) // expected-error{{protocol type 'CP' cannot conform to 'CP'; only struct/enum/class types can conform to protocols}} + blackHole(GCP()) // expected-error{{value of protocol type 'CP' cannot conform to 'CP'; only struct/enum/class types can conform to protocols}} blackHole(GAO

()) // expected-error{{'GAO' requires that 'P' be a class type}} blackHole(GAO()) blackHole(GAO()) // expected-error{{'GAO' requires that 'CP' be a class type}} @@ -89,5 +89,5 @@ func foo() { // generic no overloads error path. The error should actually talk // about the return type, and this can happen in other contexts as well; // tracks improving QoI here. - allMine.takeAll() // expected-error{{protocol type 'Mine' cannot conform to 'Mine'; only struct/enum/class types can conform to protocols}} + allMine.takeAll() // expected-error{{value of protocol type 'Mine' cannot conform to 'Mine'; only struct/enum/class types can conform to protocols}} } diff --git a/test/decl/protocol/conforms/error_self_conformance.swift b/test/decl/protocol/conforms/error_self_conformance.swift index 67db0981205fc..a5ceb7947a8c3 100644 --- a/test/decl/protocol/conforms/error_self_conformance.swift +++ b/test/decl/protocol/conforms/error_self_conformance.swift @@ -11,15 +11,15 @@ func testSimple(error: Error) { protocol ErrorRefinement : Error {} func testErrorRefinment(error: ErrorRefinement) { - wantsError(error) // expected-error {{protocol type 'ErrorRefinement' cannot conform to 'Error'; only struct/enum/class types can conform to protocols}} + wantsError(error) // expected-error {{value of protocol type 'ErrorRefinement' cannot conform to 'Error'; only struct/enum/class types can conform to protocols}} } protocol OtherProtocol {} func testErrorComposition(error: Error & OtherProtocol) { - wantsError(error) // expected-error {{protocol type 'Error & OtherProtocol' cannot conform to 'Error'; only struct/enum/class types can conform to protocols}} + wantsError(error) // expected-error {{value of protocol type 'Error & OtherProtocol' cannot conform to 'Error'; only struct/enum/class types can conform to protocols}} } class C {} func testErrorCompositionWithClass(error: Error & C) { - wantsError(error) // expected-error {{protocol type 'C & Error' cannot conform to 'Error'; only struct/enum/class types can conform to protocols}} + wantsError(error) // expected-error {{value of protocol type 'C & Error' cannot conform to 'Error'; only struct/enum/class types can conform to protocols}} } diff --git a/test/stmt/foreach.swift b/test/stmt/foreach.swift index 9b1b80b52ec4e..b6d2822b25947 100644 --- a/test/stmt/foreach.swift +++ b/test/stmt/foreach.swift @@ -179,7 +179,7 @@ func testOptionalSequence() { // Crash with (invalid) for each over an existential func testExistentialSequence(s: Sequence) { // expected-error {{protocol 'Sequence' can only be used as a generic constraint because it has Self or associated type requirements}} - for x in s { // expected-error {{protocol type 'Sequence' cannot conform to 'Sequence'; only struct/enum/class types can conform to protocols}} + for x in s { // expected-error {{value of protocol type 'Sequence' cannot conform to 'Sequence'; only struct/enum/class types can conform to protocols}} _ = x } } diff --git a/test/type/subclass_composition.swift b/test/type/subclass_composition.swift index 2c0a618a78c97..291b343145936 100644 --- a/test/type/subclass_composition.swift +++ b/test/type/subclass_composition.swift @@ -413,7 +413,7 @@ func conformsTo & P2>( // expected-note@-2 {{expected an argument list of type '(T)'}} conformsToP1(p1) - // expected-error@-1 {{protocol type 'P1' cannot conform to 'P1'; only struct/enum/class types can conform to protocols}} + // expected-error@-1 {{value of protocol type 'P1' cannot conform to 'P1'; only struct/enum/class types can conform to protocols}} // FIXME: Following diagnostics are not great because when // `conformsTo*` methods are re-typechecked, they loose information diff --git a/validation-test/compiler_crashers_fixed/00017-llvm-foldingset-llvm-attributesetnode-nodeequals.swift b/validation-test/compiler_crashers_fixed/00017-llvm-foldingset-llvm-attributesetnode-nodeequals.swift index aae9af5957647..d58f6e86f203e 100644 --- a/validation-test/compiler_crashers_fixed/00017-llvm-foldingset-llvm-attributesetnode-nodeequals.swift +++ b/validation-test/compiler_crashers_fixed/00017-llvm-foldingset-llvm-attributesetnode-nodeequals.swift @@ -20,4 +20,4 @@ extension Bool : BooleanProtocol { func f(_ b: T) {} // expected-note@-1 {{required by global function 'f' where 'T' = 'BooleanProtocol'}} -f(true as BooleanProtocol) // expected-error {{protocol type 'BooleanProtocol' cannot conform to 'BooleanProtocol'; only struct/enum/class types can conform to protocols}} +f(true as BooleanProtocol) // expected-error {{value of protocol type 'BooleanProtocol' cannot conform to 'BooleanProtocol'; only struct/enum/class types can conform to protocols}} From ea2acc6f9509578a43f3711cf25d6bcce43ca788 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Tue, 17 Sep 2019 13:21:54 -0700 Subject: [PATCH 054/199] [Test] Update Parse/confusables.swift with the "type cannot conform" error message and note. --- test/Parse/confusables.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/Parse/confusables.swift b/test/Parse/confusables.swift index 2ce2de259c55c..d855ea122d564 100644 --- a/test/Parse/confusables.swift +++ b/test/Parse/confusables.swift @@ -17,5 +17,6 @@ if (true ꝸꝸꝸ false) {} // expected-note {{identifier 'ꝸꝸꝸ' contains // expected-error @+3 {{invalid character in source file}} // expected-error @+2 {{expected ',' separator}} -// expected-error @+1 {{argument type '(Int, Int)' does not conform to expected type 'BinaryInteger'}} +// expected-error @+1 {{type '(Int, Int)' cannot conform to 'BinaryInteger'; only struct/enum/class types can conform to protocols}} if (5 ‒ 5) == 0 {} // expected-note {{unicode character '‒' looks similar to '-'; did you mean to use '-'?}} {{7-10=-}} +// expected-note @-1 {{required by referencing operator function '==' on 'BinaryInteger' where 'Self' = '(Int, Int)'}} From 3d058c6b4ff9e5286ad3db68a109692a713814ec Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Tue, 17 Sep 2019 21:22:11 +0100 Subject: [PATCH 055/199] [Typechecker] Remove a few unnecessary isTypeContext() checks as its implifed by isInstanceMember() --- lib/Sema/TypeCheckDecl.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 8de2d9912884c..8c578ca5316bb 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -1959,9 +1959,7 @@ void TypeChecker::validateDecl(OperatorDecl *OD) { llvm::Expected SelfAccessKindRequest::evaluate(Evaluator &evaluator, FuncDecl *FD) const { if (FD->getAttrs().getAttribute(true)) { - auto functionDC = FD->getDeclContext(); - if (!FD->isInstanceMember() || - (functionDC->isTypeContext() && !functionDC->hasValueSemantics())) { + if (!FD->isInstanceMember() || !FD->getDeclContext()->hasValueSemantics()) { return SelfAccessKind::NonMutating; } return SelfAccessKind::Mutating; @@ -1983,9 +1981,7 @@ SelfAccessKindRequest::evaluate(Evaluator &evaluator, FuncDecl *FD) const { case AccessorKind::MutableAddress: case AccessorKind::Set: case AccessorKind::Modify: - auto accessorDC = AD->getDeclContext(); - if (AD->isInstanceMember() && accessorDC->isTypeContext() && - accessorDC->hasValueSemantics()) + if (AD->isInstanceMember() && AD->getDeclContext()->hasValueSemantics()) return SelfAccessKind::Mutating; break; From 6ec62d97843f752bd56915eb6b0e690b44172b15 Mon Sep 17 00:00:00 2001 From: David Ungar Date: Mon, 16 Sep 2019 16:39:35 -0700 Subject: [PATCH 056/199] Ensure that Decls aren't added needlessly before creating tree eagerly. --- lib/AST/ASTScopeCreation.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index 7a3d4113b4103..ac3d28f91065f 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -747,7 +747,6 @@ void ASTScope::buildScopeTreeEagerly() { ASTSourceFileScope *ASTScope::createScopeTree(SourceFile *SF) { ScopeCreator *scopeCreator = new (SF->getASTContext()) ScopeCreator(SF); - scopeCreator->sourceFileScope->addNewDeclsToScopeTree(); return scopeCreator->sourceFileScope; } From 7e3608e007b0540c7520bd61a19f787e9db07481 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Tue, 17 Sep 2019 13:39:52 -0700 Subject: [PATCH 057/199] [ownership] Add a new checkValue overload to LinearLifetimeChecker that validates the linear lifetime of the passed in value and returns bool to indicate success/failure. This is the first in a series of patches that begin to hide the underlying linear lifetime implementation underneath the facade of the linear lifetime checker. I only updated the users that this applies to. --- include/swift/SIL/OwnershipUtils.h | 12 ++++++++++++ lib/SIL/OwnershipUtils.cpp | 4 +--- lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp | 7 ++++--- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/include/swift/SIL/OwnershipUtils.h b/include/swift/SIL/OwnershipUtils.h index bbe7737ab0260..a7881e9ea36f4 100644 --- a/include/swift/SIL/OwnershipUtils.h +++ b/include/swift/SIL/OwnershipUtils.h @@ -170,6 +170,18 @@ class LinearLifetimeChecker { ArrayRef nonConsumingUses, ownership::ErrorBehaviorKind errorBehavior, SmallVectorImpl *leakingBlocks = nullptr); + + /// Returns true that \p value forms a linear lifetime with consuming uses \p + /// consumingUses, non consuming uses \p nonConsumingUses. Returns false + /// otherwise. + bool validateLifetime(SILValue value, + ArrayRef consumingUses, + ArrayRef nonConsumingUses) { + return !checkValue(value, consumingUses, nonConsumingUses, + ownership::ErrorBehaviorKind::ReturnFalse, + nullptr /*leakingBlocks*/) + .getFoundError(); + } }; /// Returns true if v is an address or trivial. diff --git a/lib/SIL/OwnershipUtils.cpp b/lib/SIL/OwnershipUtils.cpp index 1d45c332fa032..b446c0c92a43a 100644 --- a/lib/SIL/OwnershipUtils.cpp +++ b/lib/SIL/OwnershipUtils.cpp @@ -207,7 +207,5 @@ bool BorrowScopeIntroducingValue::areInstructionsWithinScope( [&scratchSpace](SILInstruction *i) { scratchSpace.emplace_back(i); }); LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks); - auto result = checker.checkValue(value, scratchSpace, instructions, - ownership::ErrorBehaviorKind::ReturnFalse); - return !result.getFoundError(); + return checker.validateLifetime(value, scratchSpace, instructions); } diff --git a/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp b/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp index f606369010107..fd42982c9adfe 100644 --- a/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp +++ b/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp @@ -673,9 +673,10 @@ class StorageGuaranteesLoadVisitor SmallPtrSet visitedBlocks; LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks()); - auto result = checker.checkValue(baseObject, baseEndBorrows, valueDestroys, - ownership::ErrorBehaviorKind::ReturnFalse); - return answer(result.getFoundError()); + // Returns true on success. So we invert. + bool foundError = + !checker.validateLifetime(baseObject, baseEndBorrows, valueDestroys); + return answer(foundError); } // TODO: Handle other access kinds? From 85e6f73b1f40c27e96e34bed52d783259c040e0e Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Tue, 17 Sep 2019 15:21:21 -0700 Subject: [PATCH 058/199] [Diagnostics] In `MissingConformanceFailure`, if the non-conforming type comes from an argument, use the argument expression as the anchor for `diagnoseTypeCannotConform`. --- lib/Sema/CSDiagnostics.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index a3087fab3f76e..c47d89c679bca 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -598,7 +598,9 @@ bool MissingConformanceFailure::diagnoseAsError() { return true; } - if (diagnoseTypeCannotConform(anchor, nonConformingType, protocolType)) { + if (diagnoseTypeCannotConform((atParameterPos ? + getArgumentAt(Apply, *atParameterPos) : anchor), + nonConformingType, protocolType)) { return true; } From 3966d086a54f0428397e61e05cc19b618c238976 Mon Sep 17 00:00:00 2001 From: David Ungar Date: Tue, 17 Sep 2019 15:55:44 -0700 Subject: [PATCH 059/199] When ASTScope assertions fails, direct user to try disabling ASTScopes. --- include/swift/AST/ASTScope.h | 16 +++++-- lib/AST/ASTScope.cpp | 2 +- lib/AST/ASTScopeCreation.cpp | 78 ++++++++++++++++++--------------- lib/AST/ASTScopeLookup.cpp | 16 +++---- lib/AST/ASTScopeSourceRange.cpp | 37 +++++++++------- 5 files changed, 84 insertions(+), 65 deletions(-) diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index 74f77f9fc6fca..428923cacecd3 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -38,6 +38,16 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" +/// In case there's a bug in the ASTScope lookup system, suggest that the user +/// try disabling it. +#define ASTScopeAssert(predicate) \ + assert((predicate) && "Try compiling with '-disable-astScope-lookup'.")) + +/// \p message must be a string literal +#define ASTScopeAssert(predicate, message) \ + assert((predicate) && message \ + " Try compiling with '-disable-astScope-lookup'.") + namespace swift { #pragma mark Forward-references @@ -162,7 +172,7 @@ class ASTScopeImpl { void *operator new(size_t bytes, const ASTContext &ctx, unsigned alignment = alignof(ASTScopeImpl)); void *operator new(size_t Bytes, void *Mem) { - assert(Mem); + ASTScopeAssert(Mem); return Mem; } @@ -552,7 +562,7 @@ class Portion { void *operator new(size_t bytes, const ASTContext &ctx, unsigned alignment = alignof(ASTScopeImpl)); void *operator new(size_t Bytes, void *Mem) { - assert(Mem); + ASTScopeAssert(Mem); return Mem; } @@ -1080,7 +1090,7 @@ class AttachedPropertyWrapperScope final : public ASTScopeImpl { AttachedPropertyWrapperScope(VarDecl *e) : decl(e), sourceRangeWhenCreated(getSourceRangeOfVarDecl(e)) { - assert(sourceRangeWhenCreated.isValid()); + ASTScopeAssert(sourceRangeWhenCreated.isValid()); } virtual ~AttachedPropertyWrapperScope() {} diff --git a/lib/AST/ASTScope.cpp b/lib/AST/ASTScope.cpp index c996ed2707221..220f3526203e3 100644 --- a/lib/AST/ASTScope.cpp +++ b/lib/AST/ASTScope.cpp @@ -178,7 +178,7 @@ NullablePtr BraceStmtScope::getDeclContext() const { NullablePtr DefaultArgumentInitializerScope::getDeclContext() const { auto *dc = decl->getDefaultArgumentInitContext(); - assert(dc && "If scope exists, this must exist"); + ASTScopeAssert(dc, "If scope exists, this must exist"); return dc; } diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index ac3d28f91065f..a64ccc53426ad 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -300,9 +300,9 @@ class ScopeCreator final { // IDE/complete_property_delegate_attribute.swift fails because we try to // expand a member whose source range is backwards. (void)SM; - assert((d->getStartLoc().isInvalid() || - !SM.isBeforeInBuffer(d->getEndLoc(), d->getStartLoc())) && - "end-before-start will break tree search via location"); + ASTScopeAssert(d->getStartLoc().isInvalid() || + !SM.isBeforeInBuffer(d->getEndLoc(), d->getStartLoc()), + "end-before-start will break tree search via location"); return true; } @@ -313,8 +313,8 @@ class ScopeCreator final { template ASTScopeImpl *constructExpandAndInsertUncheckable(ASTScopeImpl *parent, Args... args) { - assert(!Scope(args...).getReferrent() && - "Not checking for duplicate ASTNode but class supports it"); + ASTScopeAssert(!Scope(args...).getReferrent(), + "Not checking for duplicate ASTNode but class supports it"); return constructExpandAndInsert(parent, args...); } @@ -322,8 +322,9 @@ class ScopeCreator final { NullablePtr ifUniqueConstructExpandAndInsert(ASTScopeImpl *parent, Args... args) { Scope dryRun(args...); - assert(dryRun.getReferrent() && - "Checking for duplicate ASTNode but class does not support it"); + ASTScopeAssert( + dryRun.getReferrent(), + "Checking for duplicate ASTNode but class does not support it"); if (scopedNodes.insert(&dryRun)) return constructExpandAndInsert(parent, args...); return nullptr; @@ -347,8 +348,8 @@ class ScopeCreator final { return ip; } ASTScopeImpl *insertionPoint = child->expandAndBeCurrent(*this); - assert(child->verifyThatThisNodeComeAfterItsPriorSibling() && - "Ensure search will work"); + ASTScopeAssert(child->verifyThatThisNodeComeAfterItsPriorSibling(), + "Ensure search will work"); return insertionPoint; } @@ -488,9 +489,8 @@ class ScopeCreator final { expansion.push_back(cond); if (clause.isActive) { // rdar://53922172 - assert(isInAnActiveNode && "Clause should not be marked " - "active unless it's context is " - "active"); + ASTScopeAssert(isInAnActiveNode, "Clause should not be marked active " + "unless it's context is active"); // get inactive nodes that nest in active clauses for (auto n : clause.Elements) { if (auto *const d = n.dyn_cast()) @@ -513,8 +513,9 @@ class ScopeCreator final { // When working on rdar://53971116 may have to cull more. std::vector culled; llvm::copy_if(input, std::back_inserter(culled), [&](ASTNode n) { - assert(!n.isDecl(DeclKind::Accessor) && - "Should not find accessors in iterable types or brace statements"); + ASTScopeAssert( + !n.isDecl(DeclKind::Accessor), + "Should not find accessors in iterable types or brace statements"); return isLocalizable(n) && !n.isDecl(DeclKind::Var) && !n.isDecl(DeclKind::EnumCase); }); @@ -617,7 +618,8 @@ class ScopeCreator final { dumpRangeable(n2, llvm::errs()); } #endif - assert(startOrder * endOrder != -1 && "Start order contradicts end order"); + ASTScopeAssert(startOrder * endOrder != -1, + "Start order contradicts end order"); return startOrder + endOrder < 1; } @@ -636,11 +638,13 @@ class ScopeCreator final { // they get created directly by the pattern code. // Doing otherwise distorts the source range // of their parents. - assert(!n.isDecl(DeclKind::Accessor) && "Should not see accessors here"); + ASTScopeAssert(!n.isDecl(DeclKind::Accessor), + "Should not see accessors here"); // Can occur in illegal code if (auto *const s = n.dyn_cast()) { if (auto *const bs = dyn_cast(s)) - assert(bs->getNumElements() == 0 && "Might mess up insertion point"); + ASTScopeAssert(bs->getNumElements() == 0, + "Might mess up insertion point"); } return !n.isDecl(DeclKind::Var); } @@ -730,7 +734,7 @@ class ScopeCreator final { void *operator new(size_t bytes, const ASTContext &ctx, unsigned alignment = alignof(ScopeCreator)); void *operator new(size_t Bytes, void *Mem) { - assert(Mem); + ASTScopeAssert(Mem); return Mem; } }; @@ -759,7 +763,7 @@ void ASTSourceFileScope::buildScopeTreeEagerly() { } void ASTSourceFileScope::addNewDeclsToScopeTree() { - assert(SF && scopeCreator); + ASTScopeAssert(false && SF && scopeCreator); ArrayRef decls = SF->Decls; // Assume that decls are only added at the end, in source order ArrayRef newDecls = decls.slice(numberOfDeclsAlreadySeen); @@ -769,7 +773,7 @@ void ASTSourceFileScope::addNewDeclsToScopeTree() { numberOfDeclsAlreadySeen = SF->Decls.size(); // Too slow to perform all the time: - // assert(scopeCreator->containsAllDeclContextsFromAST() && + // ASTScopeAssert(scopeCreator->containsAllDeclContextsFromAST(), // "ASTScope tree missed some DeclContexts or made some up"); } @@ -1056,7 +1060,7 @@ void ASTScopeImpl::addChild(ASTScopeImpl *child, ASTContext &ctx) { haveAddedCleanup = true; } storedChildren.push_back(child); - assert(!child->getParent() && "child should not already have parent"); + ASTScopeAssert(!child->getParent(), "child should not already have parent"); child->parent = this; clearCachedSourceRangesOfMeAndAncestors(); // It's possible that some callees do lookups back into the tree. @@ -1083,11 +1087,13 @@ void ASTScopeImpl::disownDescendants(ScopeCreator &scopeCreator) { ASTScopeImpl *ASTScopeImpl::expandAndBeCurrent(ScopeCreator &scopeCreator) { auto *insertionPoint = expandSpecifically(scopeCreator); if (scopeCreator.shouldBeLazy()) { - assert(!insertionPointForDeferredExpansion() || - insertionPointForDeferredExpansion().get() == insertionPoint); + ASTScopeAssert(!insertionPointForDeferredExpansion() || + insertionPointForDeferredExpansion().get() == + insertionPoint, + ""); } beCurrent(); - assert(checkSourceRangeAfterExpansion(scopeCreator.getASTContext())); + ASTScopeAssert(checkSourceRangeAfterExpansion(scopeCreator.getASTContext())); return insertionPoint; } @@ -1177,9 +1183,9 @@ PatternEntryDeclScope::expandAScopeThatCreatesANewInsertionPoint( // we cannot make a scope for it, since no source range. if (patternEntry.getOriginalInit() && isLocalizable(patternEntry.getOriginalInit())) { - assert( + ASTScopeAssert( !getSourceManager().isBeforeInBuffer( - patternEntry.getOriginalInit()->getStartLoc(), decl->getStartLoc()) && + patternEntry.getOriginalInit()->getStartLoc(), decl->getStartLoc()), "Original inits are always after the '='"); scopeCreator .constructExpandAndInsertUncheckable( @@ -1189,8 +1195,8 @@ PatternEntryDeclScope::expandAScopeThatCreatesANewInsertionPoint( forEachVarDeclWithLocalizableAccessors(scopeCreator, [&](VarDecl *var) { scopeCreator.ifUniqueConstructExpandAndInsert(this, var); }); - assert(!handleUseBeforeDef && - "next line is wrong otherwise; would need a use scope"); + ASTScopeAssert(!handleUseBeforeDef, + "next line is wrong otherwise; would need a use scope"); return {getParent().get(), "When not handling use-before-def, succeeding " "code just goes in the same scope as this one"}; @@ -1482,7 +1488,7 @@ void DefaultArgumentInitializerScope:: expandAScopeThatDoesNotCreateANewInsertionPoint( ScopeCreator &scopeCreator) { auto *initExpr = decl->getDefaultValue(); - assert(initExpr); + ASTScopeAssert(initExpr); scopeCreator.addToScopeTree(initExpr, this); } @@ -1597,8 +1603,8 @@ AbstractPatternEntryScope::AbstractPatternEntryScope( PatternBindingDecl *declBeingScoped, unsigned entryIndex, DeclVisibilityKind vis) : decl(declBeingScoped), patternEntryIndex(entryIndex), vis(vis) { - assert(entryIndex < declBeingScoped->getPatternList().size() && - "out of bounds"); + ASTScopeAssert(entryIndex < declBeingScoped->getPatternList().size(), + "out of bounds"); } void AbstractPatternEntryScope::forEachVarDeclWithLocalizableAccessors( @@ -1647,7 +1653,7 @@ bool ASTScopeImpl::isATypeDeclScope() const { void ScopeCreator::forEachClosureIn( Expr *expr, function_ref, ClosureExpr *)> foundClosure) { - assert(expr); + ASTScopeAssert(expr); /// AST walker that finds top-level closures in an expression. class ClosureFinder : public ASTWalker { @@ -1864,7 +1870,7 @@ bool PatternEntryDeclScope::isCurrent() const { if (initWhenLastExpanded != getPatternEntry().getOriginalInit()) return false; if (assumeVarsDoNotGetAdded && varCountWhenLastExpanded) { - assert(varCountWhenLastExpanded == countVars(getPatternEntry())); + ASTScopeAssert(varCountWhenLastExpanded == countVars(getPatternEntry())); return true; } return countVars(getPatternEntry()) == varCountWhenLastExpanded; @@ -1903,14 +1909,14 @@ std::vector ASTScopeImpl::rescueScopesToReuse() { void ASTScopeImpl::addReusedScopes(ArrayRef scopesToAdd) { auto *p = getParentOfRescuedScopes().getPtrOrNull(); if (!p) { - assert(scopesToAdd.empty() && "Non-empty body disappeared?!"); + ASTScopeAssert(scopesToAdd.empty(), "Non-empty body disappeared?!"); return; } auto &ctx = getASTContext(); for (auto *s : scopesToAdd) { p->addChild(s, ctx); - assert(s->verifyThatThisNodeComeAfterItsPriorSibling() && - "Ensure search will work"); + ASTScopeAssert(s->verifyThatThisNodeComeAfterItsPriorSibling(), + "Ensure search will work"); } } diff --git a/lib/AST/ASTScopeLookup.cpp b/lib/AST/ASTScopeLookup.cpp index 7db3b840963b7..edad17505ad01 100644 --- a/lib/AST/ASTScopeLookup.cpp +++ b/lib/AST/ASTScopeLookup.cpp @@ -94,10 +94,10 @@ const ASTScopeImpl *ASTScopeImpl::findStartingScopeForLookup( // fileScope->dump(); llvm::errs() << "\n\n"; - assert(fileScope->crossCheckWithAST()); + ASTScopeAssert(fileScope->crossCheckWithAST()); } - assert(startingScope && "ASTScopeImpl: could not find startingScope"); + ASTScopeAssert(startingScope, "ASTScopeImpl: could not find startingScope"); return startingScope; } @@ -122,7 +122,7 @@ const ASTScopeImpl *ASTScopeImpl::findInnermostEnclosingScopeImpl( bool ASTScopeImpl::checkSourceRangeOfThisASTNode() const { const auto r = getSourceRangeOfThisASTNode(); (void)r; - assert(!getSourceManager().isBeforeInBuffer(r.End, r.Start)); + ASTScopeAssert(!getSourceManager().isBeforeInBuffer(r.End, r.Start)); return true; } @@ -134,12 +134,12 @@ ASTScopeImpl::findChildContaining(SourceLoc loc, SourceManager &sourceMgr; bool operator()(const ASTScopeImpl *scope, SourceLoc loc) { - assert(scope->checkSourceRangeOfThisASTNode()); + ASTScopeAssert(scope->checkSourceRangeOfThisASTNode()); return sourceMgr.isBeforeInBuffer(scope->getSourceRangeOfScope().End, loc); } bool operator()(SourceLoc loc, const ASTScopeImpl *scope) { - assert(scope->checkSourceRangeOfThisASTNode()); + ASTScopeAssert(scope->checkSourceRangeOfThisASTNode()); return sourceMgr.isBeforeInBuffer(loc, scope->getSourceRangeOfScope().End); } @@ -382,7 +382,7 @@ bool AbstractFunctionBodyScope::lookupLocalsOrMembers( bool MethodBodyScope::lookupLocalsOrMembers( ArrayRef history, DeclConsumer consumer) const { - assert(isAMethod(decl)); + ASTScopeAssert(isAMethod(decl)); if (AbstractFunctionBodyScope::lookupLocalsOrMembers(history, consumer)) return true; return consumer.consume({decl->getImplicitSelfDecl()}, @@ -391,7 +391,7 @@ bool MethodBodyScope::lookupLocalsOrMembers( bool PureFunctionBodyScope::lookupLocalsOrMembers( ArrayRef history, DeclConsumer consumer) const { - assert(!isAMethod(decl)); + ASTScopeAssert(!isAMethod(decl)); if (AbstractFunctionBodyScope::lookupLocalsOrMembers(history, consumer)) return true; @@ -490,7 +490,7 @@ bool ASTScopeImpl::lookupLocalBindingsInPattern(Pattern *p, NullablePtr GenericTypeOrExtensionWhereOrBodyPortion::computeSelfDC( ArrayRef history) { - assert(history.size() != 0 && "includes current scope"); + ASTScopeAssert(history.size() != 0, "includes current scope"); size_t i = history.size() - 1; // skip last entry (this scope) while (i != 0) { Optional> maybeSelfDC = diff --git a/lib/AST/ASTScopeSourceRange.cpp b/lib/AST/ASTScopeSourceRange.cpp index 47d5fb869dd6d..f79734429ed8a 100644 --- a/lib/AST/ASTScopeSourceRange.cpp +++ b/lib/AST/ASTScopeSourceRange.cpp @@ -52,7 +52,7 @@ SourceRange ASTScopeImpl::widenSourceRangeForChildren(const SourceRange range, const bool omitAssertions) const { if (getChildren().empty()) { - assert(omitAssertions || range.Start.isValid()); + ASTScopeAssert(omitAssertions || range.Start.isValid()); return range; } const auto childStart = @@ -60,7 +60,7 @@ ASTScopeImpl::widenSourceRangeForChildren(const SourceRange range, const auto childEnd = getChildren().back()->getSourceRangeOfScope(omitAssertions).End; auto childRange = SourceRange(childStart, childEnd); - assert(omitAssertions || childRange.isValid()); + ASTScopeAssert(omitAssertions || childRange.isValid()); if (range.isInvalid()) return childRange; @@ -70,12 +70,14 @@ ASTScopeImpl::widenSourceRangeForChildren(const SourceRange range, } bool ASTScopeImpl::checkSourceRangeAfterExpansion(const ASTContext &ctx) const { - assert((getSourceRangeOfThisASTNode().isValid() || !getChildren().empty()) && - "need to be able to find source range"); - assert(verifyThatChildrenAreContainedWithin(getSourceRangeOfScope()) && - "Search will fail"); - assert(checkLazySourceRange(ctx) && - "Lazy scopes must have compatible ranges before and after expansion"); + ASTScopeAssert(getSourceRangeOfThisASTNode().isValid() || + !getChildren().empty(), + "need to be able to find source range"); + ASTScopeAssert(verifyThatChildrenAreContainedWithin(getSourceRangeOfScope()), + "Search will fail"); + ASTScopeAssert( + checkLazySourceRange(ctx), + "Lazy scopes must have compatible ranges before and after expansion"); return true; } @@ -160,7 +162,7 @@ NullablePtr ASTScopeImpl::getPriorSibling() const { break; } } - assert(myIndex != -1 && "I have been disowned!"); + ASTScopeAssert(myIndex != -1, "I have been disowned!"); if (myIndex == 0) return nullptr; return siblingsAndMe[myIndex - 1]; @@ -293,7 +295,7 @@ SourceRange GenericTypeOrExtensionWholePortion::getChildlessSourceRangeOf( auto *d = scope->getDecl(); auto r = d->getSourceRangeIncludingAttrs(); if (r.Start.isValid()) { - assert(r.End.isValid()); + ASTScopeAssert(r.End.isValid()); return r; } return d->getSourceRange(); @@ -322,7 +324,7 @@ SourceRange AbstractFunctionDeclScope::getSourceRangeOfThisASTNode( // them at the start location of the accessor. auto r = decl->getSourceRangeIncludingAttrs(); if (r.Start.isValid()) { - assert(r.End.isValid()); + ASTScopeAssert(r.End.isValid()); return r; } return decl->getBodySourceRange(); @@ -334,9 +336,9 @@ SourceRange ParameterListScope::getSourceRangeOfThisASTNode( getSourceRangeOfEnclosedParamsOfASTNode(omitAssertions); auto r = SourceRange(rangeForGoodInput.Start, fixupEndForBadInput(rangeForGoodInput)); - assert(getSourceManager().rangeContains( - getParent().get()->getSourceRangeOfThisASTNode(true), r) && - "Parameters not within function?!"); + ASTScopeAssert(getSourceManager().rangeContains( + getParent().get()->getSourceRangeOfThisASTNode(true), r), + "Parameters not within function?!"); return r; } @@ -423,8 +425,8 @@ CaptureListScope::getSourceRangeOfThisASTNode(const bool omitAssertions) const { SourceRange ClosureParametersScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { if (!omitAssertions) - assert(closureExpr->getInLoc().isValid() && - "We don't create these if no in loc"); + ASTScopeAssert(closureExpr->getInLoc().isValid(), + "We don't create these if no in loc"); return SourceRange(getStartOfFirstParam(closureExpr), closureExpr->getInLoc()); } @@ -458,7 +460,8 @@ ASTScopeImpl::getSourceRangeOfScope(const bool omitAssertions) const { bool ASTScopeImpl::isSourceRangeCached(const bool omitAssertions) const { const bool isCached = cachedSourceRange.hasValue(); - assert(omitAssertions || isCached || ensureNoAncestorsSourceRangeIsCached()); + ASTScopeAssert(omitAssertions || isCached || + ensureNoAncestorsSourceRangeIsCached()); return isCached; } From 8ebba23b06dd07fcdf105871b5184cb955a14b38 Mon Sep 17 00:00:00 2001 From: David Ungar Date: Tue, 17 Sep 2019 16:02:43 -0700 Subject: [PATCH 060/199] Add ASTScope_unreachable --- include/swift/AST/ASTScope.h | 3 +++ lib/AST/ASTScopeCreation.cpp | 18 ++++++++++-------- lib/AST/ASTScopeLookup.cpp | 4 ++-- lib/AST/ASTScopeSourceRange.cpp | 6 +++--- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index 428923cacecd3..352c36166c0ae 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -48,6 +48,9 @@ assert((predicate) && message \ " Try compiling with '-disable-astScope-lookup'.") +#define ASTScope_unreachable(message) \ + llvm_unreachable(message " Try compiling with '-disable-astScope-lookup'.") + namespace swift { #pragma mark Forward-references diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index a64ccc53426ad..d94d526e16b5c 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -335,7 +335,7 @@ class ScopeCreator final { Args... args) { if (auto s = ifUniqueConstructExpandAndInsert(parent, args...)) return s.get(); - llvm_unreachable("Scope should have been unique"); + ASTScope_unreachable("Scope should have been unique"); } private: @@ -578,13 +578,13 @@ class ScopeCreator final { dumpPBD(pbd, "prev"); if (auto *pbd = dyn_cast(d)) { dumpPBD(pbd, "curr"); - llvm_unreachable("found colliding pattern binding decls"); + ASTScope_unreachable("found colliding pattern binding decls"); } llvm::errs() << "Two same kind decls at same loc: \n"; lastD->dump(llvm::errs()); llvm::errs() << "and\n"; d->dump(llvm::errs()); - llvm_unreachable("Two same kind decls; unexpected kinds"); + ASTScope_unreachable("Two same kind decls; unexpected kinds"); } } @@ -764,6 +764,7 @@ void ASTSourceFileScope::buildScopeTreeEagerly() { void ASTSourceFileScope::addNewDeclsToScopeTree() { ASTScopeAssert(false && SF && scopeCreator); + ASTScope_unreachable("gazorp"); ArrayRef decls = SF->Decls; // Assume that decls are only added at the end, in source order ArrayRef newDecls = decls.slice(numberOfDeclsAlreadySeen); @@ -899,7 +900,7 @@ class NodeAdder #pragma mark special-case creation ASTScopeImpl *visitSourceFile(SourceFile *, ASTScopeImpl *, ScopeCreator &) { - llvm_unreachable("SourceFiles are orphans."); + ASTScope_unreachable("SourceFiles are orphans."); } NullablePtr visitYieldStmt(YieldStmt *ys, ASTScopeImpl *p, @@ -977,8 +978,9 @@ class NodeAdder NullablePtr visitIfConfigDecl(IfConfigDecl *icd, ASTScopeImpl *p, ScopeCreator &scopeCreator) { - llvm_unreachable("Should be handled inside of " - "expandIfConfigClausesThenCullAndSortElementsOrMembers"); + ASTScope_unreachable( + "Should be handled inside of " + "expandIfConfigClausesThenCullAndSortElementsOrMembers"); } NullablePtr visitReturnStmt(ReturnStmt *rs, ASTScopeImpl *p, @@ -1234,7 +1236,7 @@ ConditionalClauseScope::expandAScopeThatCreatesANewInsertionPoint( return {ccPatternUseScope, "Succeeding code must be in scope of conditional variables"}; } - llvm_unreachable("Unhandled StmtConditionKind in switch"); + ASTScope_unreachable("Unhandled StmtConditionKind in switch"); } AnnotatedInsertionPoint @@ -1293,7 +1295,7 @@ TopLevelCodeScope::expandAScopeThatCreatesANewInsertionPoint(ScopeCreator & void ASTSourceFileScope::expandAScopeThatDoesNotCreateANewInsertionPoint( ScopeCreator &scopeCreator) { - llvm_unreachable("expanded by addNewDeclsToScopeTree()"); + ASTScope_unreachable("expanded by addNewDeclsToScopeTree()"); } // Create child scopes for every declaration in a body. diff --git a/lib/AST/ASTScopeLookup.cpp b/lib/AST/ASTScopeLookup.cpp index edad17505ad01..c49b44008ccc2 100644 --- a/lib/AST/ASTScopeLookup.cpp +++ b/lib/AST/ASTScopeLookup.cpp @@ -168,7 +168,7 @@ bool ASTScopeImpl::doesContextMatchStartingContext( if (auto p = getParent()) return p.get()->doesContextMatchStartingContext(context); // Topmost scope always has a context, the SourceFile. - llvm_unreachable("topmost scope always has a context, the SourceFile"); + ASTScope_unreachable("topmost scope always has a context, the SourceFile"); } // For a SubscriptDecl with generic parameters, the call tries to do lookups @@ -631,7 +631,7 @@ Optional GenericParamScope::resolveIsCascadingUseForThisScope( Optional isCascadingUse) const { if (auto *dc = getDeclContext().getPtrOrNull()) return ifUnknownIsCascadingUseAccordingTo(isCascadingUse, dc); - llvm_unreachable("generic what?"); + ASTScope_unreachable("generic what?"); } Optional AbstractFunctionDeclScope::resolveIsCascadingUseForThisScope( diff --git a/lib/AST/ASTScopeSourceRange.cpp b/lib/AST/ASTScopeSourceRange.cpp index f79734429ed8a..b4291ee871bb5 100644 --- a/lib/AST/ASTScopeSourceRange.cpp +++ b/lib/AST/ASTScopeSourceRange.cpp @@ -145,7 +145,7 @@ bool ASTScopeImpl::verifyThatThisNodeComeAfterItsPriorSibling() const { // .getRangeForBuffer( // getSourceFile()->getBufferID().getValue()) // .str(); - llvm_unreachable("unexpected out-of-order nodes"); + ASTScope_unreachable("unexpected out-of-order nodes"); return false; } @@ -315,7 +315,7 @@ SourceRange IterableTypeBodyPortion::getChildlessSourceRangeOf( return e->getBraces(); if (omitAssertions) return SourceRange(); - llvm_unreachable("No body!"); + ASTScope_unreachable("No body!"); } SourceRange AbstractFunctionDeclScope::getSourceRangeOfThisASTNode( @@ -470,7 +470,7 @@ bool ASTScopeImpl::ensureNoAncestorsSourceRangeIsCached() const { auto r = !p->isSourceRangeCached(true) && p->ensureNoAncestorsSourceRangeIsCached(); if (!r) - llvm_unreachable("found a violation"); + ASTScope_unreachable("found a violation"); return true; } return true; From e3f776015411952d2bcb37d71cc75d2a37cf370b Mon Sep 17 00:00:00 2001 From: David Ungar Date: Tue, 17 Sep 2019 16:23:37 -0700 Subject: [PATCH 061/199] Add explanations to all asserts. --- include/swift/AST/ASTScope.h | 10 ++++------ lib/AST/ASTScopeCreation.cpp | 22 ++++++++++++++-------- lib/AST/ASTScopeLookup.cpp | 16 ++++++++++------ lib/AST/ASTScopeSourceRange.cpp | 11 ++++++----- 4 files changed, 34 insertions(+), 25 deletions(-) diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index 352c36166c0ae..50b37036bf42a 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -40,9 +40,6 @@ /// In case there's a bug in the ASTScope lookup system, suggest that the user /// try disabling it. -#define ASTScopeAssert(predicate) \ - assert((predicate) && "Try compiling with '-disable-astScope-lookup'.")) - /// \p message must be a string literal #define ASTScopeAssert(predicate, message) \ assert((predicate) && message \ @@ -175,7 +172,7 @@ class ASTScopeImpl { void *operator new(size_t bytes, const ASTContext &ctx, unsigned alignment = alignof(ASTScopeImpl)); void *operator new(size_t Bytes, void *Mem) { - ASTScopeAssert(Mem); + ASTScopeAssert(Mem, "Allocation failed"); return Mem; } @@ -565,7 +562,7 @@ class Portion { void *operator new(size_t bytes, const ASTContext &ctx, unsigned alignment = alignof(ASTScopeImpl)); void *operator new(size_t Bytes, void *Mem) { - ASTScopeAssert(Mem); + ASTScopeAssert(Mem, "Allocation failed"); return Mem; } @@ -1093,7 +1090,8 @@ class AttachedPropertyWrapperScope final : public ASTScopeImpl { AttachedPropertyWrapperScope(VarDecl *e) : decl(e), sourceRangeWhenCreated(getSourceRangeOfVarDecl(e)) { - ASTScopeAssert(sourceRangeWhenCreated.isValid()); + ASTScopeAssert(sourceRangeWhenCreated.isValid(), + "VarDecls must have ranges to be looked-up"); } virtual ~AttachedPropertyWrapperScope() {} diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index d94d526e16b5c..ad7b2f43169ba 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -734,7 +734,7 @@ class ScopeCreator final { void *operator new(size_t bytes, const ASTContext &ctx, unsigned alignment = alignof(ScopeCreator)); void *operator new(size_t Bytes, void *Mem) { - ASTScopeAssert(Mem); + ASTScopeAssert(Mem, "Allocation failed"); return Mem; } }; @@ -763,8 +763,8 @@ void ASTSourceFileScope::buildScopeTreeEagerly() { } void ASTSourceFileScope::addNewDeclsToScopeTree() { - ASTScopeAssert(false && SF && scopeCreator); - ASTScope_unreachable("gazorp"); + ASTScopeAssert(SF && scopeCreator, + "Must already have a SourceFile and a ScopeCreator."); ArrayRef decls = SF->Decls; // Assume that decls are only added at the end, in source order ArrayRef newDecls = decls.slice(numberOfDeclsAlreadySeen); @@ -1092,10 +1092,13 @@ ASTScopeImpl *ASTScopeImpl::expandAndBeCurrent(ScopeCreator &scopeCreator) { ASTScopeAssert(!insertionPointForDeferredExpansion() || insertionPointForDeferredExpansion().get() == insertionPoint, - ""); + "In order for lookups into lazily-expanded scopes to be " + "accurate before expansion, the insertion point before " + "expansion must be the same as after expansion."); } beCurrent(); - ASTScopeAssert(checkSourceRangeAfterExpansion(scopeCreator.getASTContext())); + ASTScopeAssert(checkSourceRangeAfterExpansion(scopeCreator.getASTContext()), + "Bad range."); return insertionPoint; } @@ -1490,7 +1493,8 @@ void DefaultArgumentInitializerScope:: expandAScopeThatDoesNotCreateANewInsertionPoint( ScopeCreator &scopeCreator) { auto *initExpr = decl->getDefaultValue(); - ASTScopeAssert(initExpr); + ASTScopeAssert(initExpr, + "Default argument initializer must have an initializer."); scopeCreator.addToScopeTree(initExpr, this); } @@ -1655,7 +1659,8 @@ bool ASTScopeImpl::isATypeDeclScope() const { void ScopeCreator::forEachClosureIn( Expr *expr, function_ref, ClosureExpr *)> foundClosure) { - ASTScopeAssert(expr); + ASTScopeAssert(expr, + "If looking for closures, must have an expression to search."); /// AST walker that finds top-level closures in an expression. class ClosureFinder : public ASTWalker { @@ -1872,7 +1877,8 @@ bool PatternEntryDeclScope::isCurrent() const { if (initWhenLastExpanded != getPatternEntry().getOriginalInit()) return false; if (assumeVarsDoNotGetAdded && varCountWhenLastExpanded) { - ASTScopeAssert(varCountWhenLastExpanded == countVars(getPatternEntry())); + ASTScopeAssert(varCountWhenLastExpanded == countVars(getPatternEntry()), + "Vars were not supposed to be added to a pattern entry."); return true; } return countVars(getPatternEntry()) == varCountWhenLastExpanded; diff --git a/lib/AST/ASTScopeLookup.cpp b/lib/AST/ASTScopeLookup.cpp index c49b44008ccc2..84dc649250e66 100644 --- a/lib/AST/ASTScopeLookup.cpp +++ b/lib/AST/ASTScopeLookup.cpp @@ -94,7 +94,8 @@ const ASTScopeImpl *ASTScopeImpl::findStartingScopeForLookup( // fileScope->dump(); llvm::errs() << "\n\n"; - ASTScopeAssert(fileScope->crossCheckWithAST()); + ASTScopeAssert(fileScope->crossCheckWithAST(), + "Tree creation missed some DeclContexts."); } ASTScopeAssert(startingScope, "ASTScopeImpl: could not find startingScope"); @@ -122,7 +123,8 @@ const ASTScopeImpl *ASTScopeImpl::findInnermostEnclosingScopeImpl( bool ASTScopeImpl::checkSourceRangeOfThisASTNode() const { const auto r = getSourceRangeOfThisASTNode(); (void)r; - ASTScopeAssert(!getSourceManager().isBeforeInBuffer(r.End, r.Start)); + ASTScopeAssert(!getSourceManager().isBeforeInBuffer(r.End, r.Start), + "Range is backwards."); return true; } @@ -134,12 +136,12 @@ ASTScopeImpl::findChildContaining(SourceLoc loc, SourceManager &sourceMgr; bool operator()(const ASTScopeImpl *scope, SourceLoc loc) { - ASTScopeAssert(scope->checkSourceRangeOfThisASTNode()); + ASTScopeAssert(scope->checkSourceRangeOfThisASTNode(), "Bad range."); return sourceMgr.isBeforeInBuffer(scope->getSourceRangeOfScope().End, loc); } bool operator()(SourceLoc loc, const ASTScopeImpl *scope) { - ASTScopeAssert(scope->checkSourceRangeOfThisASTNode()); + ASTScopeAssert(scope->checkSourceRangeOfThisASTNode(), "Bad range."); return sourceMgr.isBeforeInBuffer(loc, scope->getSourceRangeOfScope().End); } @@ -382,7 +384,7 @@ bool AbstractFunctionBodyScope::lookupLocalsOrMembers( bool MethodBodyScope::lookupLocalsOrMembers( ArrayRef history, DeclConsumer consumer) const { - ASTScopeAssert(isAMethod(decl)); + ASTScopeAssert(isAMethod(decl), "Asking for members of a non-method."); if (AbstractFunctionBodyScope::lookupLocalsOrMembers(history, consumer)) return true; return consumer.consume({decl->getImplicitSelfDecl()}, @@ -391,7 +393,9 @@ bool MethodBodyScope::lookupLocalsOrMembers( bool PureFunctionBodyScope::lookupLocalsOrMembers( ArrayRef history, DeclConsumer consumer) const { - ASTScopeAssert(!isAMethod(decl)); + ASTScopeAssert( + !isAMethod(decl), + "Should have called lookupLocalsOrMembers instead of this function."); if (AbstractFunctionBodyScope::lookupLocalsOrMembers(history, consumer)) return true; diff --git a/lib/AST/ASTScopeSourceRange.cpp b/lib/AST/ASTScopeSourceRange.cpp index b4291ee871bb5..685b85fd1b546 100644 --- a/lib/AST/ASTScopeSourceRange.cpp +++ b/lib/AST/ASTScopeSourceRange.cpp @@ -52,7 +52,7 @@ SourceRange ASTScopeImpl::widenSourceRangeForChildren(const SourceRange range, const bool omitAssertions) const { if (getChildren().empty()) { - ASTScopeAssert(omitAssertions || range.Start.isValid()); + ASTScopeAssert(omitAssertions || range.Start.isValid(), "Bad range."); return range; } const auto childStart = @@ -60,7 +60,7 @@ ASTScopeImpl::widenSourceRangeForChildren(const SourceRange range, const auto childEnd = getChildren().back()->getSourceRangeOfScope(omitAssertions).End; auto childRange = SourceRange(childStart, childEnd); - ASTScopeAssert(omitAssertions || childRange.isValid()); + ASTScopeAssert(omitAssertions || childRange.isValid(), "Bad range."); if (range.isInvalid()) return childRange; @@ -295,7 +295,7 @@ SourceRange GenericTypeOrExtensionWholePortion::getChildlessSourceRangeOf( auto *d = scope->getDecl(); auto r = d->getSourceRangeIncludingAttrs(); if (r.Start.isValid()) { - ASTScopeAssert(r.End.isValid()); + ASTScopeAssert(r.End.isValid(), "Start valid imples end valid."); return r; } return d->getSourceRange(); @@ -324,7 +324,7 @@ SourceRange AbstractFunctionDeclScope::getSourceRangeOfThisASTNode( // them at the start location of the accessor. auto r = decl->getSourceRangeIncludingAttrs(); if (r.Start.isValid()) { - ASTScopeAssert(r.End.isValid()); + ASTScopeAssert(r.End.isValid(), "Start valid imples end valid."); return r; } return decl->getBodySourceRange(); @@ -461,7 +461,8 @@ ASTScopeImpl::getSourceRangeOfScope(const bool omitAssertions) const { bool ASTScopeImpl::isSourceRangeCached(const bool omitAssertions) const { const bool isCached = cachedSourceRange.hasValue(); ASTScopeAssert(omitAssertions || isCached || - ensureNoAncestorsSourceRangeIsCached()); + ensureNoAncestorsSourceRangeIsCached(), + "Cached ancestor's range likely is obsolete."); return isCached; } From 9f642f0bc1713798f5e08b1020d359a64866162b Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Tue, 17 Sep 2019 16:42:44 -0700 Subject: [PATCH 062/199] Revert "Merge pull request #27203 from CodaFi/movin-on-up" This reverts commit 387d2a9aee35554d7ff62bba5a8082f3798f6d31, reversing changes made to bf1ab6c29d2b895ac75a705d981e07f53ae15828. --- include/swift/Parse/HiddenLibSyntaxAction.h | 2 + include/swift/Parse/LibSyntaxGenerator.h | 4 +- include/swift/Parse/ParsedRawSyntaxNode.h | 103 +++++- include/swift/Parse/ParsedRawSyntaxRecorder.h | 4 +- include/swift/Parse/ParsedSyntax.h | 9 +- .../swift/Parse/ParsedSyntaxRecorder.h.gyb | 25 +- include/swift/Parse/SyntaxParseActions.h | 7 + include/swift/Parse/SyntaxParserResult.h | 37 ++- include/swift/Parse/SyntaxParsingContext.h | 23 +- include/swift/SyntaxParse/SyntaxTreeCreator.h | 2 + lib/Parse/HiddenLibSyntaxAction.cpp | 9 + lib/Parse/ParseDecl.cpp | 4 +- lib/Parse/ParseExpr.cpp | 34 +- lib/Parse/ParsePattern.cpp | 1 + lib/Parse/ParseStmt.cpp | 1 + lib/Parse/ParseType.cpp | 292 +++++++++--------- lib/Parse/ParsedRawSyntaxNode.cpp | 15 +- lib/Parse/ParsedRawSyntaxRecorder.cpp | 34 +- lib/Parse/ParsedSyntaxBuilders.cpp.gyb | 4 +- lib/Parse/ParsedSyntaxNodes.cpp.gyb | 6 +- lib/Parse/ParsedSyntaxRecorder.cpp.gyb | 57 ++-- lib/Parse/Parser.cpp | 19 +- lib/Parse/SyntaxParsingContext.cpp | 88 +++--- lib/SyntaxParse/RawSyntaxTokenCache.h | 3 +- lib/SyntaxParse/SyntaxTreeCreator.cpp | 6 + test/Syntax/serialize_tupletype.swift.result | 38 +-- .../libSwiftSyntaxParser.cpp | 4 + 27 files changed, 501 insertions(+), 330 deletions(-) diff --git a/include/swift/Parse/HiddenLibSyntaxAction.h b/include/swift/Parse/HiddenLibSyntaxAction.h index 0b42bcc0c706a..7f26db622a1f2 100644 --- a/include/swift/Parse/HiddenLibSyntaxAction.h +++ b/include/swift/Parse/HiddenLibSyntaxAction.h @@ -70,6 +70,8 @@ class HiddenLibSyntaxAction : public SyntaxParseActions { std::pair lookupNode(size_t lexerOffset, syntax::SyntaxKind kind) override; + void discardRecordedNode(OpaqueSyntaxNode node) override; + OpaqueSyntaxNodeKind getOpaqueKind() override { return ExplicitAction->getOpaqueKind(); } diff --git a/include/swift/Parse/LibSyntaxGenerator.h b/include/swift/Parse/LibSyntaxGenerator.h index 66698411dcc2c..1333ed74af219 100644 --- a/include/swift/Parse/LibSyntaxGenerator.h +++ b/include/swift/Parse/LibSyntaxGenerator.h @@ -44,7 +44,7 @@ class LibSyntaxGenerator { auto Recorded = Recorder.recordToken(Kind, Range, LeadingTriviaPieces, TrailingTriviaPieces); - auto Raw = static_cast(Recorded.getOpaqueNode()); + auto Raw = static_cast(Recorded.takeOpaqueNode()); return make(Raw); } @@ -55,7 +55,7 @@ class LibSyntaxGenerator { auto Children = Node.getDeferredChildren(); auto Recorded = Recorder.recordRawSyntax(Kind, Children); - RC Raw {static_cast(Recorded.getOpaqueNode()) }; + RC Raw {static_cast(Recorded.takeOpaqueNode()) }; Raw->Release(); // -1 since it's transfer of ownership. return make(Raw); } diff --git a/include/swift/Parse/ParsedRawSyntaxNode.h b/include/swift/Parse/ParsedRawSyntaxNode.h index 5df7656e4c364..2c80ee7b89de1 100644 --- a/include/swift/Parse/ParsedRawSyntaxNode.h +++ b/include/swift/Parse/ParsedRawSyntaxNode.h @@ -51,7 +51,7 @@ class ParsedRawSyntaxNode { CharSourceRange Range; }; struct DeferredLayoutNode { - ArrayRef Children; + MutableArrayRef Children; }; struct DeferredTokenNode { const ParsedTriviaPiece *TriviaPieces; @@ -73,8 +73,8 @@ class ParsedRawSyntaxNode { bool IsMissing = false; ParsedRawSyntaxNode(syntax::SyntaxKind k, - ArrayRef deferredNodes) - : DeferredLayout{deferredNodes}, + MutableArrayRef deferredNodes) + : DeferredLayout({deferredNodes}), SynKind(uint16_t(k)), TokKind(uint16_t(tok::unknown)), DK(DataKind::DeferredLayout) { assert(getKind() == k && "Syntax kind with too large value!"); @@ -97,6 +97,8 @@ class ParsedRawSyntaxNode { assert(DeferredToken.NumTrailingTrivia == numTrailingTrivia && "numLeadingTrivia is too large value!"); } + ParsedRawSyntaxNode(ParsedRawSyntaxNode &other) = delete; + ParsedRawSyntaxNode &operator=(ParsedRawSyntaxNode &other) = delete; public: ParsedRawSyntaxNode() @@ -115,6 +117,35 @@ class ParsedRawSyntaxNode { assert(getTokenKind() == tokKind && "Token kind with too large value!"); } + ParsedRawSyntaxNode &operator=(ParsedRawSyntaxNode &&other) { + assert(DK != DataKind::Recorded); + switch (other.DK) { + case DataKind::Null: + break; + case DataKind::Recorded: + RecordedData = std::move(other.RecordedData); + break; + case DataKind::DeferredLayout: + DeferredLayout = std::move(other.DeferredLayout); + break; + case DataKind::DeferredToken: + DeferredToken = std::move(other.DeferredToken); + break; + } + SynKind = std::move(other.SynKind); + TokKind = std::move(other.TokKind); + DK = std::move(other.DK); + IsMissing = std::move(other.IsMissing); + other.reset(); + return *this; + } + ParsedRawSyntaxNode(ParsedRawSyntaxNode &&other) : ParsedRawSyntaxNode() { + *this = std::move(other); + } + ~ParsedRawSyntaxNode() { + assert(DK != DataKind::Recorded); + } + syntax::SyntaxKind getKind() const { return syntax::SyntaxKind(SynKind); } tok getTokenKind() const { return tok(TokKind); } @@ -136,6 +167,36 @@ class ParsedRawSyntaxNode { /// Primary used for a deferred missing token. bool isMissing() const { return IsMissing; } + void reset() { + RecordedData = {}; + SynKind = uint16_t(syntax::SyntaxKind::Unknown); + TokKind = uint16_t(tok::unknown); + DK = DataKind::Null; + IsMissing = false; + } + + ParsedRawSyntaxNode unsafeCopy() const { + ParsedRawSyntaxNode copy; + switch (DK) { + case DataKind::DeferredLayout: + copy.DeferredLayout = DeferredLayout; + break; + case DataKind::DeferredToken: + copy.DeferredToken = DeferredToken; + break; + case DataKind::Recorded: + copy.RecordedData = RecordedData; + break; + case DataKind::Null: + break; + } + copy.SynKind = SynKind; + copy.TokKind = TokKind; + copy.DK = DK; + copy.IsMissing = IsMissing; + return copy; + } + CharSourceRange getDeferredRange() const { switch (DK) { case DataKind::DeferredLayout: @@ -153,18 +214,24 @@ class ParsedRawSyntaxNode { assert(isRecorded()); return RecordedData.Range; } - OpaqueSyntaxNode getOpaqueNode() const { + const OpaqueSyntaxNode &getOpaqueNode() const { assert(isRecorded()); return RecordedData.OpaqueNode; } + OpaqueSyntaxNode takeOpaqueNode() { + assert(isRecorded()); + auto opaque = RecordedData.OpaqueNode; + reset(); + return opaque; + } // Deferred Layout Data ====================================================// CharSourceRange getDeferredLayoutRange() const { assert(DK == DataKind::DeferredLayout); assert(!DeferredLayout.Children.empty()); - auto getLastNonNullChild = [this]() { - for (auto &&Child : llvm::reverse(getDeferredChildren())) + auto getLastNonNullChild = [this]() -> const ParsedRawSyntaxNode & { + for (auto &Child : llvm::reverse(getDeferredChildren())) if (!Child.isNull()) return Child; llvm_unreachable("layout node without non-null children"); @@ -178,6 +245,28 @@ class ParsedRawSyntaxNode { assert(DK == DataKind::DeferredLayout); return DeferredLayout.Children; } + MutableArrayRef getDeferredChildren() { + assert(DK == DataKind::DeferredLayout); + return DeferredLayout.Children; + } + ParsedRawSyntaxNode copyDeferred() const { + ParsedRawSyntaxNode copy; + switch (DK) { + case DataKind::DeferredLayout: + copy.DeferredLayout = DeferredLayout; + break; + case DataKind::DeferredToken: + copy.DeferredToken = DeferredToken; + break; + default: + llvm_unreachable("node not deferred"); + } + copy.SynKind = SynKind; + copy.TokKind = TokKind; + copy.DK = DK; + copy.IsMissing = IsMissing; + return copy; + } // Deferred Token Data =====================================================// @@ -214,7 +303,7 @@ class ParsedRawSyntaxNode { /// Form a deferred syntax layout node. static ParsedRawSyntaxNode makeDeferred(syntax::SyntaxKind k, - ArrayRef deferredNodes, + MutableArrayRef deferredNodes, SyntaxParsingContext &ctx); /// Form a deferred token node. diff --git a/include/swift/Parse/ParsedRawSyntaxRecorder.h b/include/swift/Parse/ParsedRawSyntaxRecorder.h index 9ab897b60d7e9..1afe4837fdc76 100644 --- a/include/swift/Parse/ParsedRawSyntaxRecorder.h +++ b/include/swift/Parse/ParsedRawSyntaxRecorder.h @@ -60,7 +60,7 @@ class ParsedRawSyntaxRecorder { /// \p kind. Missing optional elements are represented with a null /// ParsedRawSyntaxNode object. ParsedRawSyntaxNode recordRawSyntax(syntax::SyntaxKind kind, - ArrayRef elements); + MutableArrayRef elements); /// Record a raw syntax collecton without eny elements. \p loc can be invalid /// or an approximate location of where an element of the collection would be @@ -68,6 +68,8 @@ class ParsedRawSyntaxRecorder { ParsedRawSyntaxNode recordEmptyRawSyntaxCollection(syntax::SyntaxKind kind, SourceLoc loc); + void discardRecordedNode(ParsedRawSyntaxNode &node); + /// Used for incremental re-parsing. ParsedRawSyntaxNode lookupNode(size_t lexerOffset, SourceLoc loc, syntax::SyntaxKind kind); diff --git a/include/swift/Parse/ParsedSyntax.h b/include/swift/Parse/ParsedSyntax.h index 61052aaa98f00..a3c9fdd52e031 100644 --- a/include/swift/Parse/ParsedSyntax.h +++ b/include/swift/Parse/ParsedSyntax.h @@ -26,6 +26,7 @@ class ParsedSyntax { : RawNode(std::move(rawNode)) {} const ParsedRawSyntaxNode &getRaw() const { return RawNode; } + ParsedRawSyntaxNode takeRaw() { return std::move(RawNode); } syntax::SyntaxKind getKind() const { return RawNode.getKind(); } /// Returns true if the syntax node is of the given type. @@ -39,7 +40,7 @@ class ParsedSyntax { template T castTo() const { assert(is() && "castTo() node of incompatible type!"); - return T { RawNode }; + return T { RawNode.copyDeferred() }; } /// If this Syntax node is of the right kind, cast and return it, @@ -52,6 +53,10 @@ class ParsedSyntax { return llvm::None; } + ParsedSyntax copyDeferred() const { + return ParsedSyntax { RawNode.copyDeferred() }; + } + static bool kindof(syntax::SyntaxKind Kind) { return true; } @@ -65,7 +70,7 @@ class ParsedSyntax { class ParsedTokenSyntax final : public ParsedSyntax { public: explicit ParsedTokenSyntax(ParsedRawSyntaxNode rawNode) - : ParsedSyntax(rawNode) {} + : ParsedSyntax(std::move(rawNode)) {} tok getTokenKind() const { return getRaw().getTokenKind(); diff --git a/include/swift/Parse/ParsedSyntaxRecorder.h.gyb b/include/swift/Parse/ParsedSyntaxRecorder.h.gyb index c81481f6ca46a..51b56c73aea07 100644 --- a/include/swift/Parse/ParsedSyntaxRecorder.h.gyb +++ b/include/swift/Parse/ParsedSyntaxRecorder.h.gyb @@ -53,15 +53,15 @@ public: % elif node.is_syntax_collection(): private: static Parsed${node.name} record${node.syntax_kind}( - ArrayRef elts, + MutableArrayRef elts, ParsedRawSyntaxRecorder &rec); public: static Parsed${node.name} defer${node.syntax_kind}( - ArrayRef elts, + MutableArrayRef elts, SyntaxParsingContext &SPCtx); static Parsed${node.name} make${node.syntax_kind}( - ArrayRef elts, + MutableArrayRef elts, SyntaxParsingContext &SPCtx); static Parsed${node.name} makeBlank${node.syntax_kind}(SourceLoc loc, @@ -69,16 +69,16 @@ public: % elif node.is_unknown(): private: static Parsed${node.name} record${node.syntax_kind}( - ArrayRef elts, + MutableArrayRef elts, ParsedRawSyntaxRecorder &rec); public: static Parsed${node.name} defer${node.syntax_kind}( - ArrayRef elts, + MutableArrayRef elts, SyntaxParsingContext &SPCtx); static Parsed${node.name} make${node.syntax_kind}( - ArrayRef elts, + MutableArrayRef elts, SyntaxParsingContext &SPCtx); % end % end @@ -95,8 +95,8 @@ public: /// optional trailing comma. static ParsedTupleTypeElementSyntax makeTupleTypeElement(ParsedTypeSyntax Type, - Optional TrailingComma, - SyntaxParsingContext &SPCtx); + Optional TrailingComma, + SyntaxParsingContext &SPCtx); /// The provided \c elements are in the appropriate order for the syntax /// \c kind's layout but optional elements are not be included. @@ -104,9 +104,12 @@ public: /// substituting missing parts with a null ParsedRawSyntaxNode object. /// /// \returns true if the layout could be formed, false otherwise. - static bool formExactLayoutFor(syntax::SyntaxKind kind, - ArrayRef elements, - function_ref)> receiver); + static bool + formExactLayoutFor(syntax::SyntaxKind kind, + MutableArrayRef elements, + function_ref)> + receiver); }; } diff --git a/include/swift/Parse/SyntaxParseActions.h b/include/swift/Parse/SyntaxParseActions.h index 2a68e132f472b..33a788ba8e1fa 100644 --- a/include/swift/Parse/SyntaxParseActions.h +++ b/include/swift/Parse/SyntaxParseActions.h @@ -61,6 +61,13 @@ class SyntaxParseActions { ArrayRef elements, CharSourceRange range) = 0; + /// Discard raw syntax node. + /// + /// FIXME: This breaks invariant that any recorded node will be a part of the + /// result SourceFile syntax. This method is a temporary workaround, and + /// should be removed when we fully migrate to libSyntax parsing. + virtual void discardRecordedNode(OpaqueSyntaxNode node) = 0; + /// Used for incremental re-parsing. virtual std::pair lookupNode(size_t lexerOffset, syntax::SyntaxKind kind) { diff --git a/include/swift/Parse/SyntaxParserResult.h b/include/swift/Parse/SyntaxParserResult.h index 28b12ee2390d1..6ee74fe398178 100644 --- a/include/swift/Parse/SyntaxParserResult.h +++ b/include/swift/Parse/SyntaxParserResult.h @@ -40,18 +40,18 @@ template class ParsedSyntaxResult { assert(Status.isError()); } - explicit ParsedSyntaxResult(ParsedRawSyntaxNode Raw) - : Raw(Raw), Status() {} + explicit ParsedSyntaxResult(ParsedRawSyntaxNode &&Raw) + : Raw(std::move(Raw)), Status() {} - explicit ParsedSyntaxResult(ParsedSyntaxNode Node) - : ParsedSyntaxResult(Node.getRaw()) {} + explicit ParsedSyntaxResult(ParsedSyntaxNode &&Node) + : ParsedSyntaxResult(Node.takeRaw()) {} template ::value>::type> - ParsedSyntaxResult(ParsedSyntaxResult other) { - Raw = other.Raw; - Status = other.Status; + ParsedSyntaxResult(ParsedSyntaxResult &&other) { + Raw = std::move(other.Raw); + Status = std::move(other.Status); } bool isSuccess() const { @@ -72,11 +72,20 @@ template class ParsedSyntaxResult { Status.setHasCodeCompletion(); } - ParsedSyntaxNode get() const { + ParsedSyntaxNode get() { assert(!isNull()); - return ParsedSyntaxNode(Raw); + return ParsedSyntaxNode(std::move(Raw)); } - Optional getOrNull() const { + + template + Optional getAs() { + assert(!isNull()); + if (NewSyntaxNode::kindof(Raw.getKind())) + return NewSyntaxNode(std::move(Raw)); + return None; + } + + Optional getOrNull() { if (isNull()) return None; return get(); @@ -94,13 +103,13 @@ template class ParsedSyntaxResult { template static ParsedSyntaxResult makeParsedResult(ParsedSyntaxNode node) { - return ParsedSyntaxResult(node); + return ParsedSyntaxResult(std::move(node)); } template static ParsedSyntaxResult makeParsedError(ParsedSyntaxNode node) { - auto result = ParsedSyntaxResult(node); + auto result = ParsedSyntaxResult(std::move(node)); result.setIsError(); return result; } @@ -113,7 +122,7 @@ static ParsedSyntaxResult makeParsedError() { template static ParsedSyntaxResult makeParsedCodeCompletion(ParsedSyntaxNode node) { - auto result = ParsedSyntaxResult(node); + auto result = ParsedSyntaxResult(std::move(node)); result.setHasCodeCompletion(); return result; } @@ -121,7 +130,7 @@ makeParsedCodeCompletion(ParsedSyntaxNode node) { template static ParsedSyntaxResult makeParsedResult(ParsedSyntaxNode node, ParserStatus Status) { - auto result = ParsedSyntaxResult(node); + auto result = ParsedSyntaxResult(std::move(node)); if (Status.hasCodeCompletion()) result.setHasCodeCompletion(); else if (Status.isError()) diff --git a/include/swift/Parse/SyntaxParsingContext.h b/include/swift/Parse/SyntaxParsingContext.h index 383060ddffc10..2db8e6e9058c1 100644 --- a/include/swift/Parse/SyntaxParsingContext.h +++ b/include/swift/Parse/SyntaxParsingContext.h @@ -180,14 +180,17 @@ class alignas(1 << SyntaxAlignInBits) SyntaxParsingContext { ArrayRef getParts() const { return llvm::makeArrayRef(getStorage()).drop_front(Offset); } + MutableArrayRef getParts() { + return llvm::makeMutableArrayRef(getStorage().data(), getStorage().size()).drop_front(Offset); + } ParsedRawSyntaxNode makeUnknownSyntax(SyntaxKind Kind, - ArrayRef Parts); + MutableArrayRef Parts); ParsedRawSyntaxNode createSyntaxAs(SyntaxKind Kind, - ArrayRef Parts, + MutableArrayRef Parts, SyntaxNodeCreationKind nodeCreateK); Optional bridgeAs(SyntaxContextKind Kind, - ArrayRef Parts); + MutableArrayRef Parts); ParsedRawSyntaxNode finalizeSourceFile(); @@ -277,14 +280,12 @@ class alignas(1 << SyntaxAlignInBits) SyntaxParsingContext { /// Returns the topmost Syntax node. template SyntaxNode topNode() { - ParsedRawSyntaxNode TopNode = getStorage().back(); - + ParsedRawSyntaxNode &TopNode = getStorage().back(); if (TopNode.isRecorded()) { OpaqueSyntaxNode OpaqueNode = TopNode.getOpaqueNode(); return getSyntaxCreator().getLibSyntaxNodeFor(OpaqueNode); } - - return getSyntaxCreator().createNode(TopNode); + return getSyntaxCreator().createNode(TopNode.copyDeferred()); } template @@ -292,14 +293,14 @@ class alignas(1 << SyntaxAlignInBits) SyntaxParsingContext { auto &Storage = getStorage(); if (Storage.size() <= Offset) return llvm::None; - auto rawNode = Storage.back(); - if (!SyntaxNode::kindof(rawNode.getKind())) + if (!SyntaxNode::kindof(Storage.back().getKind())) return llvm::None; + auto rawNode = std::move(Storage.back()); Storage.pop_back(); - return SyntaxNode(rawNode); + return SyntaxNode(std::move(rawNode)); } - ParsedTokenSyntax popToken(); + ParsedTokenSyntax &&popToken(); /// Create a node using the tail of the collected parts. The number of parts /// is automatically determined from \c Kind. Node: limited number of \c Kind diff --git a/include/swift/SyntaxParse/SyntaxTreeCreator.h b/include/swift/SyntaxParse/SyntaxTreeCreator.h index 26202fa8d7e72..73af22262299b 100644 --- a/include/swift/SyntaxParse/SyntaxTreeCreator.h +++ b/include/swift/SyntaxParse/SyntaxTreeCreator.h @@ -64,6 +64,8 @@ class SyntaxTreeCreator: public SyntaxParseActions { ArrayRef elements, CharSourceRange range) override; + void discardRecordedNode(OpaqueSyntaxNode node) override; + std::pair lookupNode(size_t lexerOffset, syntax::SyntaxKind kind) override; diff --git a/lib/Parse/HiddenLibSyntaxAction.cpp b/lib/Parse/HiddenLibSyntaxAction.cpp index 9185acf6c7e96..023d01158bae2 100644 --- a/lib/Parse/HiddenLibSyntaxAction.cpp +++ b/lib/Parse/HiddenLibSyntaxAction.cpp @@ -125,3 +125,12 @@ HiddenLibSyntaxAction::getExplicitNodeFor(OpaqueSyntaxNode node) { auto hiddenNode = (Node *)node; return hiddenNode->ExplicitActionNode; } + +void HiddenLibSyntaxAction::discardRecordedNode(OpaqueSyntaxNode opaqueN) { + if (!opaqueN) + return; + auto node = static_cast(opaqueN); + if (!areBothLibSyntax()) + LibSyntaxAction->discardRecordedNode(node->LibSyntaxNode); + ExplicitAction->discardRecordedNode(node->ExplicitActionNode); +} diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 599d3ee5b6c6f..a4d2514c0b2ab 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -4125,7 +4125,7 @@ parseDeclTypeAlias(Parser::ParseDeclOptions Flags, DeclAttributes &Attributes) { ParserPosition startPosition = getParserPosition(); llvm::Optional TmpCtxt; TmpCtxt.emplace(SyntaxContext); - TmpCtxt->setTransparent(); + TmpCtxt->setBackTracking(); SourceLoc TypeAliasLoc = consumeToken(tok::kw_typealias); SourceLoc EqualLoc; @@ -4164,13 +4164,13 @@ parseDeclTypeAlias(Parser::ParseDeclOptions Flags, DeclAttributes &Attributes) { } if (Flags.contains(PD_InProtocol) && !genericParams && !Tok.is(tok::equal)) { - TmpCtxt->setBackTracking(); TmpCtxt.reset(); // If we're in a protocol and don't see an '=' this looks like leftover Swift 2 // code intending to be an associatedtype. backtrackToPosition(startPosition); return parseDeclAssociatedType(Flags, Attributes); } + TmpCtxt->setTransparent(); TmpCtxt.reset(); auto *TAD = new (Context) TypeAliasDecl(TypeAliasLoc, EqualLoc, Id, IdLoc, diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 625b10a384705..211cf97860f73 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -1312,25 +1312,25 @@ ParserResult Parser::parseExprPostfix(Diag<> ID, bool isExprBasic) { template <> ParsedExprSyntax Parser::parseExprSyntax() { auto Token = consumeTokenSyntax(tok::integer_literal); - return ParsedSyntaxRecorder::makeIntegerLiteralExpr(Token, *SyntaxContext); + return ParsedSyntaxRecorder::makeIntegerLiteralExpr(std::move(Token), *SyntaxContext); } template <> ParsedExprSyntax Parser::parseExprSyntax() { auto Token = consumeTokenSyntax(tok::floating_literal); - return ParsedSyntaxRecorder::makeFloatLiteralExpr(Token, *SyntaxContext); + return ParsedSyntaxRecorder::makeFloatLiteralExpr(std::move(Token), *SyntaxContext); } template <> ParsedExprSyntax Parser::parseExprSyntax() { auto Token = consumeTokenSyntax(tok::kw_nil); - return ParsedSyntaxRecorder::makeNilLiteralExpr(Token, *SyntaxContext); + return ParsedSyntaxRecorder::makeNilLiteralExpr(std::move(Token), *SyntaxContext); } template <> ParsedExprSyntax Parser::parseExprSyntax() { auto Token = consumeTokenSyntax(); - return ParsedSyntaxRecorder::makeBooleanLiteralExpr(Token, *SyntaxContext); + return ParsedSyntaxRecorder::makeBooleanLiteralExpr(std::move(Token), *SyntaxContext); } template <> @@ -1341,11 +1341,11 @@ ParsedExprSyntax Parser::parseExprSyntax() { .fixItReplace(Tok.getLoc(), fixit); auto Token = consumeTokenSyntax(tok::kw___FILE__); - return ParsedSyntaxRecorder::makeUnknownExpr({Token}, *SyntaxContext); + return ParsedSyntaxRecorder::makeUnknownExpr({&Token, 1}, *SyntaxContext); } auto Token = consumeTokenSyntax(tok::pound_file); - return ParsedSyntaxRecorder::makePoundFileExpr(Token, *SyntaxContext); + return ParsedSyntaxRecorder::makePoundFileExpr(std::move(Token), *SyntaxContext); } template <> @@ -1356,12 +1356,12 @@ ParsedExprSyntax Parser::parseExprSyntax() { .fixItReplace(Tok.getLoc(), fixit); auto Token = consumeTokenSyntax(tok::kw___LINE__); - return ParsedSyntaxRecorder::makeUnknownExpr({Token}, *SyntaxContext); + return ParsedSyntaxRecorder::makeUnknownExpr({&Token, 1}, *SyntaxContext); } // FIXME: #line was renamed to #sourceLocation auto Token = consumeTokenSyntax(tok::pound_line); - return ParsedSyntaxRecorder::makePoundLineExpr(Token, *SyntaxContext); + return ParsedSyntaxRecorder::makePoundLineExpr(std::move(Token), *SyntaxContext); } template <> @@ -1372,11 +1372,11 @@ ParsedExprSyntax Parser::parseExprSyntax() { .fixItReplace(Tok.getLoc(), fixit); auto Token = consumeTokenSyntax(tok::kw___COLUMN__); - return ParsedSyntaxRecorder::makeUnknownExpr({Token}, *SyntaxContext); + return ParsedSyntaxRecorder::makeUnknownExpr({&Token, 1}, *SyntaxContext); } auto Token = consumeTokenSyntax(tok::pound_column); - return ParsedSyntaxRecorder::makePoundColumnExpr(Token, *SyntaxContext); + return ParsedSyntaxRecorder::makePoundColumnExpr(std::move(Token), *SyntaxContext); } template <> @@ -1387,11 +1387,11 @@ ParsedExprSyntax Parser::parseExprSyntax() { .fixItReplace(Tok.getLoc(), fixit); auto Token = consumeTokenSyntax(tok::kw___FUNCTION__); - return ParsedSyntaxRecorder::makeUnknownExpr({Token}, *SyntaxContext); + return ParsedSyntaxRecorder::makeUnknownExpr({&Token, 1}, *SyntaxContext); } auto Token = consumeTokenSyntax(tok::pound_function); - return ParsedSyntaxRecorder::makePoundFunctionExpr(Token, *SyntaxContext); + return ParsedSyntaxRecorder::makePoundFunctionExpr(std::move(Token), *SyntaxContext); } template <> @@ -1402,18 +1402,18 @@ ParsedExprSyntax Parser::parseExprSyntax() { .fixItReplace(Tok.getLoc(), fixit); auto Token = consumeTokenSyntax(tok::kw___DSO_HANDLE__); - return ParsedSyntaxRecorder::makeUnknownExpr({Token}, *SyntaxContext); + return ParsedSyntaxRecorder::makeUnknownExpr({&Token, 1}, *SyntaxContext); } auto Token = consumeTokenSyntax(tok::pound_dsohandle); - return ParsedSyntaxRecorder::makePoundDsohandleExpr(Token, *SyntaxContext); + return ParsedSyntaxRecorder::makePoundDsohandleExpr(std::move(Token), *SyntaxContext); } template ParserResult Parser::parseExprAST() { auto Loc = leadingTriviaLoc(); auto ParsedExpr = parseExprSyntax(); - SyntaxContext->addSyntax(ParsedExpr); + SyntaxContext->addSyntax(std::move(ParsedExpr)); // todo [gsoc]: improve this somehow if (SyntaxContext->isTopNode()) { auto Expr = SyntaxContext->topNode(); @@ -1519,9 +1519,9 @@ ParserResult Parser::parseExprPrimary(Diag<> ID, bool isExprBasic) { ParsedSyntaxRecorder::makeIdentifierPattern( SyntaxContext->popToken(), *SyntaxContext); ParsedExprSyntax ExprNode = - ParsedSyntaxRecorder::deferUnresolvedPatternExpr(PatternNode, + ParsedSyntaxRecorder::deferUnresolvedPatternExpr(std::move(PatternNode), *SyntaxContext); - SyntaxContext->addSyntax(ExprNode); + SyntaxContext->addSyntax(std::move(ExprNode)); return makeParserResult(new (Context) UnresolvedPatternExpr(pattern)); } diff --git a/lib/Parse/ParsePattern.cpp b/lib/Parse/ParsePattern.cpp index 9cb81c42d6ee4..3046decc2db7d 100644 --- a/lib/Parse/ParsePattern.cpp +++ b/lib/Parse/ParsePattern.cpp @@ -1169,6 +1169,7 @@ ParserResult Parser::parseMatchingPattern(bool isExprBasic) { // matching-pattern ::= expr // Fall back to expression parsing for ambiguous forms. Name lookup will // disambiguate. + DeferringContextRAII Deferring(*SyntaxContext); ParserResult subExpr = parseExprImpl(diag::expected_pattern, isExprBasic); ParserStatus status = subExpr; diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 61241c4ff742f..ad4811cc96336 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -123,6 +123,7 @@ ParserStatus Parser::parseExprOrStmt(ASTNode &Result) { if (Tok.is(tok::pound) && Tok.isAtStartOfLine() && peekToken().is(tok::code_complete)) { + SyntaxParsingContext CCCtxt(SyntaxContext, SyntaxContextKind::Decl); consumeToken(); if (CodeCompletion) CodeCompletion->completeAfterPoundDirective(); diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index ffa1edf33d6b6..7b4eaf46862a9 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -181,8 +181,8 @@ Parser::TypeResult Parser::parseTypeSimple(Diag<> MessageID, // Eat the code completion token because we handled it. auto CCTok = consumeTokenSyntax(tok::code_complete); ParsedTypeSyntax ty = - ParsedSyntaxRecorder::makeUnknownType({CCTok}, *SyntaxContext); - return makeParsedCodeCompletion(ty); + ParsedSyntaxRecorder::makeUnknownType({&CCTok, 1}, *SyntaxContext); + return makeParsedCodeCompletion(std::move(ty)); } case tok::l_square: Result = parseTypeCollection(); @@ -203,9 +203,10 @@ Parser::TypeResult Parser::parseTypeSimple(Diag<> MessageID, } if (Tok.isKeyword() && !Tok.isAtStartOfLine()) { + auto token = consumeTokenSyntax(); ParsedTypeSyntax ty = ParsedSyntaxRecorder::makeUnknownType( - {consumeTokenSyntax()}, *SyntaxContext); - return makeParsedError(ty); + {&token, 1}, *SyntaxContext); + return makeParsedError(std::move(ty)); } checkForInputIncomplete(); @@ -256,7 +257,7 @@ Parser::parseTypeSyntax(Diag<> messageID, bool HandleCodeCompletion, auto tyR = parseType(messageID, HandleCodeCompletion, IsSILFuncDecl); if (auto ty = SyntaxContext->popIf()) { Generator.addType(tyR.getPtrOrNull(), loc); - return makeParsedResult(*ty, tyR.getStatus()); + return makeParsedResult(std::move(*ty), tyR.getStatus()); } return tyR.getStatus(); } @@ -269,7 +270,7 @@ Parser::TypeASTResult Parser::parseSILBoxType(GenericParamList *generics, const TypeAttributes &attrs, Optional &GenericsScope) { auto LBraceLoc = consumeToken(tok::l_brace); - + SmallVector Fields; if (!Tok.is(tok::r_brace)) { for (;;) { @@ -283,30 +284,30 @@ Parser::TypeASTResult Parser::parseSILBoxType(GenericParamList *generics, return makeParserError(); } SourceLoc VarOrLetLoc = consumeToken(); - + auto fieldTy = parseType(); if (!fieldTy.getPtrOrNull()) return makeParserError(); Fields.push_back({VarOrLetLoc, Mutable, fieldTy.get()}); - + if (consumeIf(tok::comma)) continue; - + break; } } - + if (!Tok.is(tok::r_brace)) { diagnose(Tok, diag::sil_box_expected_r_brace); return makeParserError(); } - + auto RBraceLoc = consumeToken(tok::r_brace); - + // The generic arguments are taken from the enclosing scope. Pop the // box layout's scope now. GenericsScope.reset(); - + SourceLoc LAngleLoc, RAngleLoc; SmallVector Args; if (Tok.isContextualPunctuator("<")) { @@ -324,7 +325,7 @@ Parser::TypeASTResult Parser::parseSILBoxType(GenericParamList *generics, diagnose(Tok, diag::sil_box_expected_r_angle); return makeParserError(); } - + RAngleLoc = consumeToken(); } @@ -370,7 +371,7 @@ Parser::TypeASTResult Parser::parseType(Diag<> MessageID, GenericsScope.emplace(this, ScopeKind::Generics); generics = maybeParseGenericParams().getPtrOrNull(); } - + // In SIL mode, parse box types { ... }. if (isInSILMode() && Tok.is(tok::l_brace)) { auto SILBoxType = parseSILBoxType(generics, attrs, GenericsScope); @@ -407,7 +408,7 @@ Parser::TypeASTResult Parser::parseType(Diag<> MessageID, } if (Tok.is(tok::arrow)) { - auto InputNode = SyntaxContext->popIf().getValue(); + auto InputNode(std::move(SyntaxContext->popIf().getValue())); // Handle type-function if we have an arrow. auto ArrowLoc = Tok.getLoc(); auto Arrow = consumeTokenSyntax(); @@ -422,16 +423,15 @@ Parser::TypeASTResult Parser::parseType(Diag<> MessageID, parseType(diag::expected_type_function_result); auto SecondTy = SyntaxContext->popIf(); if (SecondHalf.isParseError()) { - SyntaxContext->addSyntax(InputNode); + SyntaxContext->addSyntax(std::move(InputNode)); if (Throws) - SyntaxContext->addSyntax(*Throws); - SyntaxContext->addSyntax(Arrow); + SyntaxContext->addSyntax(std::move(*Throws)); + SyntaxContext->addSyntax(std::move(Arrow)); if (SecondTy) - SyntaxContext->addSyntax(*SecondTy); + SyntaxContext->addSyntax(std::move(*SecondTy)); if (SecondHalf.hasCodeCompletion()) return makeParserCodeCompletionResult(); - if (SecondHalf.isNull()) - return nullptr; + return makeParserErrorResult(); } ParsedFunctionTypeSyntaxBuilder Builder(*SyntaxContext); @@ -442,9 +442,9 @@ Parser::TypeASTResult Parser::parseType(Diag<> MessageID, auto Arguments = TupleTypeNode->getDeferredElements(); auto RightParen = TupleTypeNode->getDeferredRightParen(); Builder - .useLeftParen(LeftParen) - .useArguments(Arguments) - .useRightParen(RightParen); + .useLeftParen(std::move(LeftParen)) + .useArguments(std::move(Arguments)) + .useRightParen(std::move(RightParen)); } else { // FIXME(syntaxparse): Extract 'Void' text from recoreded node. if (const auto Void = dyn_cast(tyR)) @@ -460,14 +460,13 @@ Parser::TypeASTResult Parser::parseType(Diag<> MessageID, .fixItInsertAfter(tyR->getEndLoc(), ")"); } Builder.addArgumentsMember(ParsedSyntaxRecorder::makeTupleTypeElement( - InputNode, /*TrailingComma=*/None, *SyntaxContext)); + std::move(InputNode), /*TrailingComma=*/None, *SyntaxContext)); } - Builder.useReturnType(*SecondTy); if (Throws) - Builder.useThrowsOrRethrowsKeyword(*Throws); - Builder.useArrow(Arrow); - Builder.useReturnType(*SecondTy); + Builder.useThrowsOrRethrowsKeyword(std::move(*Throws)); + Builder.useArrow(std::move(Arrow)); + Builder.useReturnType(std::move(*SecondTy)); SyntaxContext->addSyntax(Builder.build()); @@ -628,7 +627,7 @@ Parser::parseGenericArgumentsAST(SmallVectorImpl &ArgsAST, } /// parseTypeIdentifier -/// +/// /// type-identifier: /// identifier generic-args? ('.' identifier generic-args?)* /// @@ -642,9 +641,10 @@ Parser::TypeResult Parser::parseTypeIdentifier() { if (CodeCompletion) CodeCompletion->completeTypeSimpleBeginning(); + auto CCTok = consumeTokenSyntax(tok::code_complete); auto ty = ParsedSyntaxRecorder::makeUnknownType( - {consumeTokenSyntax(tok::code_complete)}, *SyntaxContext); - return makeParsedCodeCompletion(ty); + {&CCTok, 1}, *SyntaxContext); + return makeParsedCodeCompletion(std::move(ty)); } diagnose(Tok, diag::expected_identifier_for_type); @@ -652,9 +652,10 @@ Parser::TypeResult Parser::parseTypeIdentifier() { // If there is a keyword at the start of a new line, we won't want to // skip it as a recovery but rather keep it. if (Tok.isKeyword() && !Tok.isAtStartOfLine()) { + auto kwTok = consumeTokenSyntax(); ParsedTypeSyntax ty = ParsedSyntaxRecorder::makeUnknownType( - {consumeTokenSyntax()}, *SyntaxContext); - return makeParsedError(ty); + {&kwTok, 1}, *SyntaxContext); + return makeParsedError(std::move(ty)); } return makeParsedError(); @@ -676,42 +677,42 @@ Parser::TypeResult Parser::parseTypeIdentifier() { // FIXME: offer a fixit: 'self' -> 'Self' Identifier = parseIdentifierSyntax(diag::expected_identifier_in_dotted_type); - if (!Identifier) { - Status.setIsParseError(); - if (Base) - Junk.push_back(*Base); - if (Period) - Junk.push_back(*Period); - } } if (Identifier) { Optional GenericArgs; - + if (startsWithLess(Tok)) { SmallVector GenericArgsAST; SourceLoc LAngleLoc, RAngleLoc; auto GenericArgsResult = parseGenericArgumentClauseSyntax(); if (GenericArgsResult.isError()) { if (Base) - Junk.push_back(*Base); + Junk.push_back(std::move(*Base)); if (Period) - Junk.push_back(*Period); - Junk.push_back(*Identifier); + Junk.push_back(std::move(*Period)); + Junk.push_back(std::move(*Identifier)); if (!GenericArgsResult.isNull()) Junk.push_back(GenericArgsResult.get()); auto ty = ParsedSyntaxRecorder::makeUnknownType(Junk, *SyntaxContext); - return makeParsedResult(ty, GenericArgsResult.getStatus()); + return makeParsedResult(std::move(ty), GenericArgsResult.getStatus()); } GenericArgs = GenericArgsResult.get(); } if (!Base) Base = ParsedSyntaxRecorder::makeSimpleTypeIdentifier( - *Identifier, GenericArgs, *SyntaxContext); + std::move(*Identifier), std::move(GenericArgs), *SyntaxContext); else Base = ParsedSyntaxRecorder::makeMemberTypeIdentifier( - *Base, *Period, *Identifier, GenericArgs, *SyntaxContext); + std::move(*Base), std::move(*Period), std::move(*Identifier), + std::move(GenericArgs), *SyntaxContext); + } else { + Status.setIsParseError(); + if (Base) + Junk.push_back(std::move(*Base)); + if (Period) + Junk.push_back(std::move(*Period)); } // Treat 'Foo.' as an attempt to write a dotted type @@ -738,17 +739,16 @@ Parser::TypeResult Parser::parseTypeIdentifier() { IdentTypeRepr *ITR = nullptr; if (Base) { - SyntaxContext->addSyntax(*Base); + SyntaxContext->addSyntax(std::move(*Base)); auto T = SyntaxContext->topNode(); - SyntaxContext->popIf(); + Junk.push_back(std::move(*SyntaxContext->popIf())); ITR = dyn_cast(Generator.generate(T, BaseLoc)); - Junk.push_back(*Base); } if (Tok.isNot(tok::code_complete)) { // We have a dot. auto Dot = consumeTokenSyntax(); - Junk.push_back(Dot); + Junk.push_back(std::move(Dot)); if (CodeCompletion) CodeCompletion->completeTypeIdentifierWithDot(ITR); } else { @@ -758,15 +758,15 @@ Parser::TypeResult Parser::parseTypeIdentifier() { // Eat the code completion token because we handled it. Junk.push_back(consumeTokenSyntax(tok::code_complete)); auto ty = ParsedSyntaxRecorder::makeUnknownType(Junk, *SyntaxContext); - return makeParsedCodeCompletion(ty); + return makeParsedCodeCompletion(std::move(ty)); } - + if (Status.isError()) { auto ty = ParsedSyntaxRecorder::makeUnknownType(Junk, *SyntaxContext); - return makeParsedError(ty); + return makeParsedError(std::move(ty)); } - return makeParsedResult(*Base); + return makeParsedResult(std::move(*Base)); } Parser::TypeASTResult @@ -803,9 +803,11 @@ Parser::parseTypeSimpleOrComposition(Diag<> MessageID, FirstSome = consumeTokenSyntax(); } - auto ApplySome = [this](ParsedTypeSyntax Type, Optional Some) { - return Some ? ParsedSyntaxRecorder::makeSomeType(*Some, Type, *SyntaxContext) - : Type; + auto ApplySome = [this](ParsedTypeSyntax Type, + Optional Some) { + return Some ? ParsedSyntaxRecorder::makeSomeType( + std::move(*Some), std::move(Type), *SyntaxContext) + : std::move(Type); }; // Parse the first type @@ -817,14 +819,15 @@ Parser::parseTypeSimpleOrComposition(Diag<> MessageID, auto FirstType = FirstTypeResult.get(); if (!Tok.isContextualPunctuator("&")) - return makeParsedResult(ApplySome(FirstType, FirstSome)); + return makeParsedResult( + ApplySome(std::move(FirstType), std::move(FirstSome))); SmallVector Elements; - + Optional Ampersand = consumeTokenSyntax(); auto FirstElement = ParsedSyntaxRecorder::makeCompositionTypeElement( - FirstType, *Ampersand, *SyntaxContext); - Elements.push_back(FirstElement); + std::move(FirstType), std::move(*Ampersand), *SyntaxContext); + Elements.push_back(std::move(FirstElement)); ParserStatus Status; @@ -848,45 +851,46 @@ Parser::parseTypeSimpleOrComposition(Diag<> MessageID, SmallVector nodes; if (FirstSome) - nodes.push_back(*FirstSome); - nodes.append(Elements.begin(), Elements.end()); + nodes.push_back(std::move(*FirstSome)); + std::move(Elements.begin(), Elements.end(), std::back_inserter(nodes)); if (NextSome) - nodes.push_back(*NextSome); + nodes.push_back(std::move(*NextSome)); nodes.push_back(NextTypeResult.get()); auto ty = ParsedSyntaxRecorder::makeUnknownType(nodes, *SyntaxContext); - return makeParsedResult(ty, Status); + return makeParsedResult(std::move(ty), Status); } - auto NextType = ApplySome(NextTypeResult.get(), NextSome); - Ampersand = Tok.isContextualPunctuator("&") - ? consumeTokenSyntax() + auto NextType = ApplySome(NextTypeResult.get(), std::move(NextSome)); + Ampersand = Tok.isContextualPunctuator("&") + ? consumeTokenSyntax() : llvm::Optional(); auto NextElement = ParsedSyntaxRecorder::makeCompositionTypeElement( - NextType, Ampersand, *SyntaxContext); - Elements.push_back(NextElement); + std::move(NextType), std::move(Ampersand), *SyntaxContext); + Elements.push_back(std::move(NextElement)); } while (Ampersand); auto ElementList = ParsedSyntaxRecorder::makeCompositionTypeElementList( Elements, *SyntaxContext); - auto Composition = - ParsedSyntaxRecorder::makeCompositionType(ElementList, *SyntaxContext); - return makeParsedResult(ApplySome(Composition, FirstSome), Status); + auto Composition = ParsedSyntaxRecorder::makeCompositionType( + std::move(ElementList), *SyntaxContext); + return makeParsedResult( + ApplySome(std::move(Composition), std::move(FirstSome)), Status); } Parser::TypeASTResult Parser::parseAnyTypeAST() { auto AnyLoc = leadingTriviaLoc(); auto ParsedAny = parseAnyType().get(); - SyntaxContext->addSyntax(ParsedAny); + SyntaxContext->addSyntax(std::move(ParsedAny)); auto Any = SyntaxContext->topNode(); return makeParserResult(Generator.generate(Any, AnyLoc)); } Parser::TypeResult Parser::parseAnyType() { auto Any = consumeTokenSyntax(tok::kw_Any); - auto Type = ParsedSyntaxRecorder::makeSimpleTypeIdentifier(Any, llvm::None, - *SyntaxContext); - return makeParsedResult(Type); + auto Type = ParsedSyntaxRecorder::makeSimpleTypeIdentifier( + std::move(Any), llvm::None, *SyntaxContext); + return makeParsedResult(std::move(Type)); } /// parseOldStyleProtocolComposition @@ -909,8 +913,8 @@ Parser::TypeResult Parser::parseOldStyleProtocolComposition() { auto LAngleLoc = Tok.getLoc(); auto LAngle = consumeStartingLessSyntax(); - Junk.push_back(Protocol); - Junk.push_back(LAngle); + Junk.push_back(Protocol.copyDeferred()); + Junk.push_back(LAngle.copyDeferred()); // Parse the type-composition-list. ParserStatus Status; @@ -924,13 +928,13 @@ Parser::TypeResult Parser::parseOldStyleProtocolComposition() { Status |= TypeResult.getStatus(); if (TypeResult.isSuccess()) { auto Type = TypeResult.get(); - Junk.push_back(Type); + Junk.push_back(Type.copyDeferred()); if (!IsAny) - Protocols.push_back(Type); + Protocols.push_back(std::move(Type)); } Comma = consumeTokenSyntaxIf(tok::comma); if (Comma) - Junk.push_back(*Comma); + Junk.push_back(Comma->copyDeferred()); } while (Comma); } @@ -939,7 +943,7 @@ Parser::TypeResult Parser::parseOldStyleProtocolComposition() { if (startsWithGreater(Tok)) { RAngleLoc = Tok.getLoc(); auto RAngle = consumeStartingGreaterSyntax(); - Junk.push_back(RAngle); + Junk.push_back(RAngle.copyDeferred()); } else { if (Status.isSuccess()) { diagnose(Tok, diag::expected_rangle_protocol); @@ -951,7 +955,7 @@ Parser::TypeResult Parser::parseOldStyleProtocolComposition() { // Skip until we hit the '>'. skipUntilGreaterInTypeListSyntax(RAngleJunk, /*protocolComposition=*/true); for (auto &&Piece : RAngleJunk) - Junk.push_back(Piece); + Junk.push_back(Piece.copyDeferred()); } if (Status.isSuccess()) { @@ -959,7 +963,7 @@ Parser::TypeResult Parser::parseOldStyleProtocolComposition() { if (Protocols.empty()) { replacement = "Any"; } else { - auto extractText = [&](ParsedTypeSyntax Type) -> StringRef { + auto extractText = [&](ParsedTypeSyntax &Type) -> StringRef { auto SourceRange = Type.getRaw().getDeferredRange(); return SourceMgr.extractText(SourceRange); }; @@ -975,7 +979,7 @@ Parser::TypeResult Parser::parseOldStyleProtocolComposition() { // Need parenthesis if the next token looks like postfix TypeRepr. // i.e. '?', '!', '.Type', '.Protocol' bool needParen = false; - needParen |= !Tok.isAtStartOfLine() && + needParen |= !Tok.isAtStartOfLine() && (isOptionalToken(Tok) || isImplicitlyUnwrappedOptionalToken(Tok)); needParen |= Tok.isAny(tok::period, tok::period_prefix); if (needParen) { @@ -1001,7 +1005,7 @@ Parser::TypeResult Parser::parseOldStyleProtocolComposition() { } auto Unknown = ParsedSyntaxRecorder::makeUnknownType(Junk, *SyntaxContext); - return makeParsedResult(Unknown); + return makeParsedResult(std::move(Unknown)); } /// parseTypeTupleBody @@ -1022,15 +1026,14 @@ Parser::TypeResult Parser::parseTypeTupleBody() { return makeParsedError(); SmallVector Junk; - + auto LParenLoc = Tok.getLoc(); auto LParen = consumeTokenSyntax(tok::l_paren); - Junk.push_back(LParen); + Junk.push_back(LParen.copyDeferred()); SmallVector Elements; SmallVector, 4> ElementsLoc; - Optional FirstEllipsis; SourceLoc FirstEllipsisLoc; Optional Comma; @@ -1055,7 +1058,7 @@ Parser::TypeResult Parser::parseTypeTupleBody() { InOut = consumeTokenSyntax(tok::kw_inout); IsInOutObsoleted = true; - LocalJunk.push_back(*InOut); + LocalJunk.push_back(InOut->copyDeferred()); } // If the label is "some", this could end up being an opaque type @@ -1078,18 +1081,18 @@ Parser::TypeResult Parser::parseTypeTupleBody() { // Consume a name. NameLoc = Tok.getLoc(); Name = consumeArgumentLabelSyntax(); - LocalJunk.push_back(*Name); + LocalJunk.push_back(Name->copyDeferred()); // If there is a second name, consume it as well. if (Tok.canBeArgumentLabel()) { SecondNameLoc = Tok.getLoc(); SecondName = consumeArgumentLabelSyntax(); - LocalJunk.push_back(*SecondName); + LocalJunk.push_back(SecondName->copyDeferred()); } // Consume the ':'. if ((Colon = consumeTokenSyntaxIf(tok::colon))) { - LocalJunk.push_back(*Colon); + LocalJunk.push_back(Colon->copyDeferred()); // If we succeed, then we successfully parsed a label. if (Backtracking) Backtracking->cancelBacktrack(); @@ -1110,19 +1113,22 @@ Parser::TypeResult Parser::parseTypeTupleBody() { // Parse the type annotation. auto TypeLoc = Tok.getLoc(); - auto Type = parseTypeSyntax(diag::expected_type); - if (Type.hasCodeCompletion() || Type.isNull()) { - Junk.append(LocalJunk.begin(), LocalJunk.end()); - if (!Type.isNull()) - Junk.push_back(Type.get()); + auto ty = parseTypeSyntax(diag::expected_type); + if (ty.hasCodeCompletion() || ty.isNull()) { + std::move(LocalJunk.begin(), LocalJunk.end(), std::back_inserter(Junk)); + if (!ty.isNull()) + Junk.push_back(ty.get()); skipListUntilDeclRBraceSyntax(Junk, LParenLoc, tok::r_paren, tok::comma); - return Type.getStatus(); + return ty.getStatus(); } if (IsInOutObsoleted) { bool IsTypeAlreadyAttributed = false; - if (auto AttributedType = Type.get().getAs()) - IsTypeAlreadyAttributed = AttributedType->getDeferredSpecifier().hasValue(); + if (auto AttributedType = ty.getAs()) { + IsTypeAlreadyAttributed = + AttributedType->getDeferredSpecifier().hasValue(); + ty = makeParsedResult(std::move(*AttributedType), ty.getStatus()); + } if (IsTypeAlreadyAttributed) { // If the parsed type is already attributed, suggest removing `inout`. @@ -1140,8 +1146,7 @@ Parser::TypeResult Parser::parseTypeTupleBody() { Tok.setKind(tok::ellipsis); auto ElementEllipsisLoc = Tok.getLoc(); ElementEllipsis = consumeTokenSyntax(); - if (!FirstEllipsis) { - FirstEllipsis = ElementEllipsis; + if (!FirstEllipsisLoc.isValid()) { FirstEllipsisLoc = ElementEllipsisLoc; } else { diagnose(ElementEllipsisLoc, diag::multiple_ellipsis_in_tuple) @@ -1159,20 +1164,22 @@ Parser::TypeResult Parser::parseTypeTupleBody() { auto InFlight = diagnose(EqualLoc, diag::tuple_type_init); if (Init.isNonNull()) InFlight.fixItRemove(SourceRange(EqualLoc, Init.get()->getEndLoc())); - auto Expr = *SyntaxContext->popIf(); - Initializer = ParsedSyntaxRecorder::makeInitializerClause(*Equal, Expr, - *SyntaxContext); + Initializer = ParsedSyntaxRecorder::makeInitializerClause( + std::move(*Equal), + std::move(*SyntaxContext->popIf()), + *SyntaxContext); } Comma = consumeTokenSyntaxIf(tok::comma); auto Element = ParsedSyntaxRecorder::makeTupleTypeElement( - InOut, Name, SecondName, Colon, Type.get(), ElementEllipsis, Initializer, - Comma, *SyntaxContext); + std::move(InOut), std::move(Name), std::move(SecondName), + std::move(Colon), ty.get(), std::move(ElementEllipsis), + std::move(Initializer), std::move(Comma), *SyntaxContext); - Junk.push_back(Element); + Junk.push_back(Element.copyDeferred()); - Elements.push_back(Element); + Elements.push_back(std::move(Element)); ElementsLoc.emplace_back(NameLoc, SecondNameLoc, TypeLoc); return makeParserSuccess(); @@ -1180,15 +1187,9 @@ Parser::TypeResult Parser::parseTypeTupleBody() { if (!Status.isSuccess()) { auto ty = ParsedSyntaxRecorder::makeUnknownType(Junk, *SyntaxContext); - return makeParsedResult(ty, Status); + return makeParsedResult(std::move(ty), Status); } - auto ElementList = - ParsedSyntaxRecorder::makeTupleTypeElementList(Elements, *SyntaxContext); - - auto TupleType = ParsedSyntaxRecorder::makeTupleType(LParen, ElementList, - *RParen, *SyntaxContext); - bool IsFunctionType = Tok.isAny(tok::arrow, tok::kw_throws, tok::kw_rethrows); auto GetNameText = [this](Optional Name) { @@ -1201,7 +1202,7 @@ Parser::TypeResult Parser::parseTypeTupleBody() { if (!IsFunctionType) { for (unsigned i = 0; i < Elements.size(); i++) { // true tuples have labels - auto Element = Elements[i]; + auto &Element = Elements[i]; SourceLoc NameLoc, SecondNameLoc, TypeLoc; std::tie(NameLoc, SecondNameLoc, TypeLoc) = ElementsLoc[i]; // If there were two names, complain. @@ -1223,7 +1224,7 @@ Parser::TypeResult Parser::parseTypeTupleBody() { for (unsigned i = 0; i < Elements.size(); i++) { // If there was a first name, complain; arguments in function types are // always unlabeled. - auto Element = Elements[i]; + auto &Element = Elements[i]; SourceLoc NameLoc, SecondNameLoc, TypeLoc; std::tie(NameLoc, SecondNameLoc, TypeLoc) = ElementsLoc[i]; if (NameLoc.isValid()) { @@ -1244,7 +1245,14 @@ Parser::TypeResult Parser::parseTypeTupleBody() { } } - return makeParsedResult(TupleType); + auto ElementList = + ParsedSyntaxRecorder::makeTupleTypeElementList(Elements, *SyntaxContext); + + auto TupleType = ParsedSyntaxRecorder::makeTupleType( + std::move(LParen), std::move(ElementList), std::move(*RParen), + *SyntaxContext); + + return makeParsedResult(std::move(TupleType)); } /// parseTypeArray - Parse the type-array production, given that we @@ -1278,9 +1286,9 @@ Parser::TypeResult Parser::parseTypeArray(ParsedTypeSyntax Base, } ParsedArrayTypeSyntaxBuilder builder(*SyntaxContext); - builder.useElementType(Base); + builder.useElementType(std::move(Base)); if (RSquare) - builder.useRightSquareBracket(*RSquare); + builder.useRightSquareBracket(std::move(*RSquare)); return makeParsedError(builder.build()); } @@ -1319,35 +1327,37 @@ Parser::TypeResult Parser::parseTypeCollection() { if (!Status.isSuccess()) { SmallVector Pieces; - Pieces.push_back(LSquare); + Pieces.push_back(std::move(LSquare)); if (ElementType) - Pieces.push_back(*ElementType); + Pieces.push_back(std::move(*ElementType)); if (Colon) - Pieces.push_back(*Colon); + Pieces.push_back(std::move(*Colon)); if (ValueType) - Pieces.push_back(*ValueType); + Pieces.push_back(std::move(*ValueType)); if (RSquare) - Pieces.push_back(*RSquare); + Pieces.push_back(std::move(*RSquare)); ParsedTypeSyntax ty = ParsedSyntaxRecorder::makeUnknownType(Pieces, *SyntaxContext); - return makeParsedResult(ty, Status); + return makeParsedResult(std::move(ty), Status); } if (Colon) return makeParsedResult(ParsedSyntaxRecorder::makeDictionaryType( - LSquare, *ElementType, *Colon, *ValueType, *RSquare, *SyntaxContext)); + std::move(LSquare), std::move(*ElementType), std::move(*Colon), + std::move(*ValueType), std::move(*RSquare), *SyntaxContext)); return makeParsedResult(ParsedSyntaxRecorder::makeArrayType( - LSquare, *ElementType, *RSquare, *SyntaxContext)); + std::move(LSquare), std::move(*ElementType), std::move(*RSquare), + *SyntaxContext)); } Parser::TypeResult Parser::parseMetatypeType(ParsedTypeSyntax Base) { auto Period = consumeTokenSyntax(); // tok::period or tok::period_prefix auto Keyword = consumeTokenSyntax(tok::identifier); // "Type" or "Protocol" auto MetatypeType = ParsedSyntaxRecorder::makeMetatypeType( - Base, Period, Keyword, *SyntaxContext); - return makeParsedResult(MetatypeType); + std::move(Base), std::move(Period), std::move(Keyword), *SyntaxContext); + return makeParsedResult(std::move(MetatypeType)); } bool Parser::isOptionalToken(const Token &T) const { @@ -1403,17 +1413,17 @@ SourceLoc Parser::consumeImplicitlyUnwrappedOptionalToken() { Parser::TypeResult Parser::parseOptionalType(ParsedTypeSyntax Base) { auto Question = consumeOptionalTokenSyntax(); - auto Optional = - ParsedSyntaxRecorder::makeOptionalType(Base, Question, *SyntaxContext); - return makeParsedResult(Optional); + auto Optional = ParsedSyntaxRecorder::makeOptionalType( + std::move(Base), std::move(Question), *SyntaxContext); + return makeParsedResult(std::move(Optional)); } Parser::TypeResult Parser::parseImplicitlyUnwrappedOptionalType(ParsedTypeSyntax Base) { auto Exclamation = consumeImplicitlyUnwrappedOptionalTokenSyntax(); auto Unwrapped = ParsedSyntaxRecorder::makeImplicitlyUnwrappedOptionalType( - Base, Exclamation, *SyntaxContext); - return makeParsedResult(Unwrapped); + std::move(Base), std::move(Exclamation), *SyntaxContext); + return makeParsedResult(std::move(Unwrapped)); } //===----------------------------------------------------------------------===// diff --git a/lib/Parse/ParsedRawSyntaxNode.cpp b/lib/Parse/ParsedRawSyntaxNode.cpp index 3ae3834b25841..608381d236e57 100644 --- a/lib/Parse/ParsedRawSyntaxNode.cpp +++ b/lib/Parse/ParsedRawSyntaxNode.cpp @@ -19,15 +19,20 @@ using namespace llvm; ParsedRawSyntaxNode ParsedRawSyntaxNode::makeDeferred(SyntaxKind k, - ArrayRef deferredNodes, + MutableArrayRef deferredNodes, SyntaxParsingContext &ctx) { if (deferredNodes.empty()) { return ParsedRawSyntaxNode(k, {}); } ParsedRawSyntaxNode *newPtr = ctx.getScratchAlloc().Allocate(deferredNodes.size()); - std::uninitialized_copy(deferredNodes.begin(), deferredNodes.end(), newPtr); - return ParsedRawSyntaxNode(k, makeArrayRef(newPtr, deferredNodes.size())); + + // uninitialized move; + auto ptr = newPtr; + for (auto &node : deferredNodes) + :: new (static_cast(ptr++)) ParsedRawSyntaxNode(std::move(node)); + + return ParsedRawSyntaxNode(k, makeMutableArrayRef(newPtr, deferredNodes.size())); } ParsedRawSyntaxNode @@ -59,13 +64,13 @@ void ParsedRawSyntaxNode::dump(llvm::raw_ostream &OS, unsigned Indent) const { for (decltype(Indent) i = 0; i < Indent; ++i) OS << ' '; OS << '('; - dumpSyntaxKind(OS, getKind()); switch (DK) { case DataKind::Null: OS << ""; break; case DataKind::Recorded: + dumpSyntaxKind(OS, getKind()); OS << " [recorded] "; if (isToken()) { dumpTokenKind(OS, getTokenKind()); @@ -74,6 +79,7 @@ void ParsedRawSyntaxNode::dump(llvm::raw_ostream &OS, unsigned Indent) const { } break; case DataKind::DeferredLayout: + dumpSyntaxKind(OS, getKind()); OS << " [deferred]"; for (const auto &child : getDeferredChildren()) { OS << "\n"; @@ -81,6 +87,7 @@ void ParsedRawSyntaxNode::dump(llvm::raw_ostream &OS, unsigned Indent) const { } break; case DataKind::DeferredToken: + dumpSyntaxKind(OS, getKind()); OS << " [deferred] "; dumpTokenKind(OS, getTokenKind()); break; diff --git a/lib/Parse/ParsedRawSyntaxRecorder.cpp b/lib/Parse/ParsedRawSyntaxRecorder.cpp index 1c064fb682670..09e81834ded7e 100644 --- a/lib/Parse/ParsedRawSyntaxRecorder.cpp +++ b/lib/Parse/ParsedRawSyntaxRecorder.cpp @@ -57,9 +57,8 @@ ParsedRawSyntaxRecorder::recordMissingToken(tok tokenKind, SourceLoc loc) { } static ParsedRawSyntaxNode -getRecordedNode(const ParsedRawSyntaxNode &node, ParsedRawSyntaxRecorder &rec) { - if (node.isNull() || node.isRecorded()) - return node; +getRecordedNode(ParsedRawSyntaxNode node, ParsedRawSyntaxRecorder &rec) { + assert(!node.isNull() && !node.isRecorded()); if (node.isDeferredLayout()) return rec.recordRawSyntax(node.getKind(), node.getDeferredChildren()); assert(node.isDeferredToken()); @@ -74,24 +73,29 @@ getRecordedNode(const ParsedRawSyntaxNode &node, ParsedRawSyntaxRecorder &rec) { ParsedRawSyntaxNode ParsedRawSyntaxRecorder::recordRawSyntax(SyntaxKind kind, - ArrayRef elements) { + MutableArrayRef elements) { CharSourceRange range; SmallVector subnodes; if (!elements.empty()) { SourceLoc offset; unsigned length = 0; - for (const auto &elem : elements) { - auto subnode = getRecordedNode(elem, *this); + for (auto &subnode : elements) { + CharSourceRange localRange; if (subnode.isNull()) { subnodes.push_back(nullptr); + } else if (subnode.isRecorded()) { + localRange = subnode.getRecordedRange(); + subnodes.push_back(subnode.takeOpaqueNode()); } else { - subnodes.push_back(subnode.getOpaqueNode()); - auto range = subnode.getRecordedRange(); - if (range.isValid()) { - if (offset.isInvalid()) - offset = range.getStart(); - length += subnode.getRecordedRange().getByteLength(); - } + auto recorded = getRecordedNode(subnode.copyDeferred(), *this); + localRange = recorded.getRecordedRange(); + subnodes.push_back(recorded.takeOpaqueNode()); + } + + if (localRange.isValid()) { + if (offset.isInvalid()) + offset = localRange.getStart(); + length += localRange.getByteLength(); } } range = CharSourceRange{offset, length}; @@ -108,6 +112,10 @@ ParsedRawSyntaxRecorder::recordEmptyRawSyntaxCollection(SyntaxKind kind, return ParsedRawSyntaxNode{kind, tok::unknown, range, n}; } +void ParsedRawSyntaxRecorder::discardRecordedNode(ParsedRawSyntaxNode &node) { + SPActions->discardRecordedNode(node.takeOpaqueNode()); +} + ParsedRawSyntaxNode ParsedRawSyntaxRecorder::lookupNode(size_t lexerOffset, SourceLoc loc, SyntaxKind kind) { diff --git a/lib/Parse/ParsedSyntaxBuilders.cpp.gyb b/lib/Parse/ParsedSyntaxBuilders.cpp.gyb index a8e662639c465..9ab3964f2b2cb 100644 --- a/lib/Parse/ParsedSyntaxBuilders.cpp.gyb +++ b/lib/Parse/ParsedSyntaxBuilders.cpp.gyb @@ -43,14 +43,14 @@ Parsed${node.name}Builder::use${child.name}(Parsed${child.type_name} ${child.nam assert(${child_elt_name}s.empty() && "use either 'use' function or 'add', not both"); % end Layout[cursorIndex(${node.name}::Cursor::${child.name})] = - ${child.name}.getRaw(); + ${child.name}.takeRaw(); return *this; } % if child_elt: Parsed${node.name}Builder & Parsed${node.name}Builder::add${child_elt_name}(Parsed${child_elt_type} ${child_elt}) { assert(Layout[cursorIndex(${node.name}::Cursor::${child.name})].isNull() && "use either 'use' function or 'add', not both"); - ${child_elt_name}s.push_back(std::move(${child_elt}.getRaw())); + ${child_elt_name}s.push_back(${child_elt}.takeRaw()); return *this; } % end diff --git a/lib/Parse/ParsedSyntaxNodes.cpp.gyb b/lib/Parse/ParsedSyntaxNodes.cpp.gyb index 0f7a13c109043..e3bb56c91812e 100644 --- a/lib/Parse/ParsedSyntaxNodes.cpp.gyb +++ b/lib/Parse/ParsedSyntaxNodes.cpp.gyb @@ -28,14 +28,14 @@ using namespace swift::syntax; % if child.is_optional: Optional Parsed${node.name}::getDeferred${child.name}() { - auto RawChild = getRaw().getDeferredChildren()[${node.name}::Cursor::${child.name}]; + auto &RawChild = getRaw().getDeferredChildren()[${node.name}::Cursor::${child.name}]; if (RawChild.isNull()) return None; - return Parsed${child.type_name} {RawChild}; + return Parsed${child.type_name} {RawChild.copyDeferred()}; } % else: Parsed${child.type_name} Parsed${node.name}::getDeferred${child.name}() { - return Parsed${child.type_name} {getRaw().getDeferredChildren()[${node.name}::Cursor::${child.name}]}; + return Parsed${child.type_name} {getRaw().getDeferredChildren()[${node.name}::Cursor::${child.name}].copyDeferred()}; } % end diff --git a/lib/Parse/ParsedSyntaxRecorder.cpp.gyb b/lib/Parse/ParsedSyntaxRecorder.cpp.gyb index 7ab92a4ffa509..b305e25e7cc8f 100644 --- a/lib/Parse/ParsedSyntaxRecorder.cpp.gyb +++ b/lib/Parse/ParsedSyntaxRecorder.cpp.gyb @@ -26,8 +26,8 @@ using namespace swift; using namespace swift::syntax; bool ParsedSyntaxRecorder::formExactLayoutFor(syntax::SyntaxKind Kind, - ArrayRef Elements, - function_ref)> receiver) { + MutableArrayRef Elements, + function_ref)> receiver) { switch (Kind) { % for node in SYNTAX_NODES: case SyntaxKind::${node.syntax_kind}: { @@ -42,16 +42,23 @@ bool ParsedSyntaxRecorder::formExactLayoutFor(syntax::SyntaxKind Kind, % if child.is_optional: Layout[${child_idx}] = ParsedRawSyntaxNode::null(); % else: + for (unsigned i = 0, e = ${child_count}; i != e; ++i) + Layout[i].reset(); return false; % end } else { - Layout[${child_idx}] = Elements[I]; + Layout[${child_idx}] = Elements[I].unsafeCopy(); ++I; } % end - if (I != Elements.size()) + if (I != Elements.size()) { + for (unsigned i = 0, e = ${child_count}; i != e; ++i) + Layout[i].reset(); return false; + } receiver(Kind, Layout); + for (unsigned i = 0, e = Elements.size(); i != e; ++i) + Elements[i].reset(); return true; % elif node.is_syntax_collection(): for (auto &E : Elements) { @@ -85,29 +92,31 @@ bool ParsedSyntaxRecorder::formExactLayoutFor(syntax::SyntaxKind Kind, Parsed${node.name} ParsedSyntaxRecorder::record${node.syntax_kind}(${child_params}, ParsedRawSyntaxRecorder &rec) { - auto raw = rec.recordRawSyntax(SyntaxKind::${node.syntax_kind}, { + ParsedRawSyntaxNode layout[] = { % for child in node.children: % if child.is_optional: - ${child.name}.hasValue() ? ${child.name}->getRaw() : ParsedRawSyntaxNode::null(), + ${child.name}.hasValue() ? ${child.name}->takeRaw() : ParsedRawSyntaxNode::null(), % else: - ${child.name}.getRaw(), + ${child.name}.takeRaw(), % end % end - }); + }; + auto raw = rec.recordRawSyntax(SyntaxKind::${node.syntax_kind}, layout); return Parsed${node.name}(std::move(raw)); } Parsed${node.name} ParsedSyntaxRecorder::defer${node.syntax_kind}(${child_params}, SyntaxParsingContext &SPCtx) { - auto raw = ParsedRawSyntaxNode::makeDeferred(SyntaxKind::${node.syntax_kind}, { + ParsedRawSyntaxNode layout[] = { % for child in node.children: % if child.is_optional: - ${child.name}.hasValue() ? ${child.name}->getRaw() : ParsedRawSyntaxNode::null(), + ${child.name}.hasValue() ? ${child.name}->takeRaw() : ParsedRawSyntaxNode::null(), % else: - ${child.name}.getRaw(), + ${child.name}.takeRaw(), % end % end - }, SPCtx); + }; + auto raw = ParsedRawSyntaxNode::makeDeferred(SyntaxKind::${node.syntax_kind}, llvm::makeMutableArrayRef(layout, ${len(node.children)}), SPCtx); return Parsed${node.name}(std::move(raw)); } @@ -122,12 +131,12 @@ ParsedSyntaxRecorder::make${node.syntax_kind}(${child_params}, % elif node.is_syntax_collection(): Parsed${node.name} ParsedSyntaxRecorder::record${node.syntax_kind}( - ArrayRef elements, + MutableArrayRef elements, ParsedRawSyntaxRecorder &rec) { SmallVector layout; layout.reserve(elements.size()); for (auto &element : elements) { - layout.push_back(element.getRaw()); + layout.push_back(element.takeRaw()); } auto raw = rec.recordRawSyntax(SyntaxKind::${node.syntax_kind}, layout); return Parsed${node.name}(std::move(raw)); @@ -135,12 +144,12 @@ ParsedSyntaxRecorder::record${node.syntax_kind}( Parsed${node.name} ParsedSyntaxRecorder::defer${node.syntax_kind}( - ArrayRef elements, + MutableArrayRef elements, SyntaxParsingContext &SPCtx) { SmallVector layout; layout.reserve(elements.size()); for (auto &element : elements) { - layout.push_back(element.getRaw()); + layout.push_back(element.takeRaw()); } auto raw = ParsedRawSyntaxNode::makeDeferred(SyntaxKind::${node.syntax_kind}, layout, SPCtx); @@ -149,7 +158,7 @@ ParsedSyntaxRecorder::defer${node.syntax_kind}( Parsed${node.name} ParsedSyntaxRecorder::make${node.syntax_kind}( - ArrayRef elements, + MutableArrayRef elements, SyntaxParsingContext &SPCtx) { if (SPCtx.shouldDefer()) return defer${node.syntax_kind}(elements, SPCtx); @@ -171,12 +180,12 @@ ParsedSyntaxRecorder::makeBlank${node.syntax_kind}(SourceLoc loc, % elif node.is_unknown(): Parsed${node.name} ParsedSyntaxRecorder::record${node.syntax_kind}( - ArrayRef elements, + MutableArrayRef elements, ParsedRawSyntaxRecorder &rec) { SmallVector layout; layout.reserve(elements.size()); for (auto &element : elements) { - layout.push_back(element.getRaw()); + layout.push_back(element.takeRaw()); } auto raw = rec.recordRawSyntax(SyntaxKind::${node.syntax_kind}, layout); return Parsed${node.name}(std::move(raw)); @@ -184,12 +193,12 @@ ParsedSyntaxRecorder::record${node.syntax_kind}( Parsed${node.name} ParsedSyntaxRecorder::defer${node.syntax_kind}( - ArrayRef elements, + MutableArrayRef elements, SyntaxParsingContext &SPCtx) { SmallVector layout; layout.reserve(elements.size()); for (auto &element : elements) { - layout.push_back(element.getRaw()); + layout.push_back(element.takeRaw()); } auto raw = ParsedRawSyntaxNode::makeDeferred(SyntaxKind::${node.syntax_kind}, layout, SPCtx); return Parsed${node.name}(std::move(raw)); @@ -197,7 +206,7 @@ ParsedSyntaxRecorder::defer${node.syntax_kind}( Parsed${node.name} ParsedSyntaxRecorder::make${node.syntax_kind}( - ArrayRef elements, + MutableArrayRef elements, SyntaxParsingContext &SPCtx) { if (SPCtx.shouldDefer()) return defer${node.syntax_kind}(elements, SPCtx); @@ -224,6 +233,6 @@ ParsedTupleTypeElementSyntax ParsedSyntaxRecorder::makeTupleTypeElement(ParsedTypeSyntax Type, llvm::Optional TrailingComma, SyntaxParsingContext &SPCtx) { - return makeTupleTypeElement(None, None, None, None, Type, None, None, - TrailingComma, SPCtx); + return makeTupleTypeElement(None, None, None, None, std::move(Type), None, None, + std::move(TrailingComma), SPCtx); } diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 62783da44f29c..f1f4febab0d51 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -684,19 +684,19 @@ void Parser::skipSingleSyntax(SmallVectorImpl &Skipped) { Skipped.push_back(consumeTokenSyntax()); skipUntilSyntax(Skipped, tok::r_paren); if (auto RParen = consumeTokenSyntaxIf(tok::r_paren)) - Skipped.push_back(*RParen); + Skipped.push_back(std::move(*RParen)); break; case tok::l_brace: Skipped.push_back(consumeTokenSyntax()); skipUntilSyntax(Skipped, tok::r_brace); if (auto RBrace = consumeTokenSyntaxIf(tok::r_brace)) - Skipped.push_back(*RBrace); + Skipped.push_back(std::move(*RBrace)); break; case tok::l_square: Skipped.push_back(consumeTokenSyntax()); skipUntilSyntax(Skipped, tok::r_square); if (auto RSquare = consumeTokenSyntaxIf(tok::r_square)) - Skipped.push_back(*RSquare); + Skipped.push_back(std::move(*RSquare)); break; case tok::pound_if: case tok::pound_else: @@ -708,7 +708,7 @@ void Parser::skipSingleSyntax(SmallVectorImpl &Skipped) { if (Tok.isAny(tok::pound_else, tok::pound_elseif)) skipSingleSyntax(Skipped); else if (auto Endif = consumeTokenSyntaxIf(tok::pound_endif)) - Skipped.push_back(*Endif); + Skipped.push_back(std::move(*Endif)); break; default: @@ -1003,12 +1003,13 @@ void Parser::skipListUntilDeclRBraceSyntax( while (Tok.isNot(T1, T2, tok::eof, tok::r_brace, tok::pound_endif, tok::pound_else, tok::pound_elseif)) { auto Comma = consumeTokenSyntaxIf(tok::comma); - if (Comma) - Skipped.push_back(*Comma); - + bool hasDelimiter = Tok.getLoc() == startLoc || Comma; bool possibleDeclStartsLine = Tok.isAtStartOfLine(); + if (Comma) + Skipped.push_back(std::move(*Comma)); + if (isStartOfDecl()) { // Could have encountered something like `_ var:` // or `let foo:` or `var:` @@ -1020,7 +1021,7 @@ void Parser::skipListUntilDeclRBraceSyntax( Parser::BacktrackingScope backtrack(*this); // Consume the let or var auto LetOrVar = consumeTokenSyntax(); - Skipped.push_back(LetOrVar); + Skipped.push_back(std::move(LetOrVar)); // If the following token is either or :, it means that // this `var` or `let` should be interpreted as a label @@ -1338,7 +1339,7 @@ Parser::parseListSyntax(tok RightK, SourceLoc LeftLoc, diagnose(Tok, diag::unexpected_separator, ",") .fixItRemove(SourceRange(Tok.getLoc())); auto Comma = consumeTokenSyntax(); - Junk.push_back(Comma); + Junk.push_back(std::move(Comma)); } SourceLoc StartLoc = Tok.getLoc(); diff --git a/lib/Parse/SyntaxParsingContext.cpp b/lib/Parse/SyntaxParsingContext.cpp index afe5298d8a095..65cf131b10373 100644 --- a/lib/Parse/SyntaxParsingContext.cpp +++ b/lib/Parse/SyntaxParsingContext.cpp @@ -54,13 +54,14 @@ size_t SyntaxParsingContext::lookupNode(size_t LexerOffset, SourceLoc Loc) { return 0; } Mode = AccumulationMode::SkippedForIncrementalUpdate; - getStorage().push_back(foundNode); - return foundNode.getRecordedRange().getByteLength(); + auto length = foundNode.getRecordedRange().getByteLength(); + getStorage().push_back(std::move(foundNode)); + return length; } ParsedRawSyntaxNode SyntaxParsingContext::makeUnknownSyntax(SyntaxKind Kind, - ArrayRef Parts) { + MutableArrayRef Parts) { assert(isUnknownKind(Kind)); if (shouldDefer()) return ParsedRawSyntaxNode::makeDeferred(Kind, Parts, *this); @@ -70,12 +71,12 @@ SyntaxParsingContext::makeUnknownSyntax(SyntaxKind Kind, ParsedRawSyntaxNode SyntaxParsingContext::createSyntaxAs(SyntaxKind Kind, - ArrayRef Parts, + MutableArrayRef Parts, SyntaxNodeCreationKind nodeCreateK) { // Try to create the node of the given syntax. ParsedRawSyntaxNode rawNode; auto &rec = getRecorder(); - auto formNode = [&](SyntaxKind kind, ArrayRef layout) { + auto formNode = [&](SyntaxKind kind, MutableArrayRef layout) { if (nodeCreateK == SyntaxNodeCreationKind::Deferred || shouldDefer()) { rawNode = ParsedRawSyntaxNode::makeDeferred(kind, layout, *this); } else { @@ -91,9 +92,9 @@ SyntaxParsingContext::createSyntaxAs(SyntaxKind Kind, Optional SyntaxParsingContext::bridgeAs(SyntaxContextKind Kind, - ArrayRef Parts) { + MutableArrayRef Parts) { if (Parts.size() == 1) { - auto RawNode = Parts.front(); + auto &RawNode = Parts.front(); SyntaxKind RawNodeKind = RawNode.getKind(); switch (Kind) { case SyntaxContextKind::Stmt: @@ -120,7 +121,7 @@ SyntaxParsingContext::bridgeAs(SyntaxContextKind Kind, // We don't need to coerce in this case. break; } - return RawNode; + return std::move(RawNode); } else if (Parts.empty()) { // Just omit the unknown node if it does not have any children return None; @@ -162,8 +163,8 @@ const SyntaxParsingContext *SyntaxParsingContext::getRoot() const { return Curr; } -ParsedTokenSyntax SyntaxParsingContext::popToken() { - return popIf().getValue(); +ParsedTokenSyntax &&SyntaxParsingContext::popToken() { + return std::move(popIf().getValue()); } /// Add Token with Trivia to the parts. @@ -181,7 +182,7 @@ void SyntaxParsingContext::addToken(Token &Tok, /// Add Syntax to the parts. void SyntaxParsingContext::addSyntax(ParsedSyntax Node) { - addRawSyntax(Node.getRaw()); + addRawSyntax(Node.takeRaw()); } void SyntaxParsingContext::createNodeInPlace(SyntaxKind Kind, size_t N, @@ -192,12 +193,10 @@ void SyntaxParsingContext::createNodeInPlace(SyntaxKind Kind, size_t N, return; } - auto I = getStorage().end() - N; - *I = createSyntaxAs(Kind, getParts().take_back(N), nodeCreateK); - - // Remove consumed parts. - if (N != 1) - getStorage().erase(I + 1, getStorage().end()); + auto node = createSyntaxAs(Kind, getParts().take_back(N), nodeCreateK); + auto &storage = getStorage(); + getStorage().erase(storage.end() - N, getStorage().end()); + getStorage().emplace_back(std::move(node)); } void SyntaxParsingContext::createNodeInPlace(SyntaxKind Kind, @@ -250,32 +249,24 @@ void SyntaxParsingContext::collectNodesInPlace(SyntaxKind ColletionKind, ParsedRawSyntaxNode SyntaxParsingContext::finalizeSourceFile() { ParsedRawSyntaxRecorder &Recorder = getRecorder(); - ArrayRef Parts = getParts(); - std::vector AllTopLevel; + auto Parts = getParts(); + ParsedRawSyntaxNode Layout[2]; assert(!Parts.empty() && Parts.back().isToken(tok::eof)); - ParsedRawSyntaxNode EOFToken = Parts.back(); + Layout[1] = std::move(Parts.back()); Parts = Parts.drop_back(); - for (auto RawNode : Parts) { - if (RawNode.getKind() != SyntaxKind::CodeBlockItem) { - // FIXME: Skip toplevel garbage nodes for now. we shouldn't emit them in - // the first place. - if (RawNode.isRecorded()) - getSyntaxCreator().finalizeNode(RawNode.getOpaqueNode()); - continue; - } + assert(llvm::all_of(Parts, [](const ParsedRawSyntaxNode& node) { + return node.getKind() == SyntaxKind::CodeBlockItem; + }) && "all top level element must be 'CodeBlockItem'"); - AllTopLevel.push_back(RawNode); - } + Layout[0] = Recorder.recordRawSyntax(SyntaxKind::CodeBlockItemList, Parts); - auto itemList = Recorder.recordRawSyntax(SyntaxKind::CodeBlockItemList, - Parts); return Recorder.recordRawSyntax(SyntaxKind::SourceFile, - { itemList, EOFToken }); + llvm::makeMutableArrayRef(Layout, 2)); } - OpaqueSyntaxNode SyntaxParsingContext::finalizeRoot() { +OpaqueSyntaxNode SyntaxParsingContext::finalizeRoot() { assert(isTopOfContextStack() && "some sub-contexts are not destructed"); assert(isRoot() && "only root context can finalize the tree"); assert(Mode == AccumulationMode::Root); @@ -283,7 +274,7 @@ ParsedRawSyntaxNode SyntaxParsingContext::finalizeSourceFile() { return nullptr; // already finalized. } ParsedRawSyntaxNode root = finalizeSourceFile(); - auto opaqueRoot = getSyntaxCreator().finalizeNode(root.getOpaqueNode()); + auto opaqueRoot = getSyntaxCreator().finalizeNode(root.takeOpaqueNode()); // Clear the parts because we will call this function again when destroying // the root context. @@ -303,9 +294,12 @@ void SyntaxParsingContext::synthesize(tok Kind, SourceLoc Loc) { void SyntaxParsingContext::dumpStorage() const { llvm::errs() << "======================\n"; - for (auto Node : getStorage()) { - Node.dump(llvm::errs()); - llvm::errs() << "\n--------------\n"; + auto &storage = getStorage(); + for (unsigned i = 0; i != storage.size(); ++i) { + storage[i].dump(llvm::errs()); + llvm::errs() << "\n"; + if (i + 1 == Offset) + llvm::errs() << "--------------\n"; } } @@ -337,14 +331,12 @@ SyntaxParsingContext::~SyntaxParsingContext() { assert(!isRoot()); if (Storage.size() == Offset) { if (auto BridgedNode = bridgeAs(CtxtKind, {})) { - Storage.push_back(BridgedNode.getValue()); + Storage.push_back(std::move(BridgedNode.getValue())); } } else { - auto I = Storage.begin() + Offset; - *I = bridgeAs(CtxtKind, getParts()).getValue(); - // Remove used parts. - if (Storage.size() > Offset + 1) - Storage.erase(Storage.begin() + (Offset + 1), Storage.end()); + auto node(std::move(bridgeAs(CtxtKind, getParts()).getValue())); + Storage.erase(Storage.begin() + Offset, Storage.end()); + Storage.emplace_back(std::move(node)); } break; } @@ -357,10 +349,12 @@ SyntaxParsingContext::~SyntaxParsingContext() { // Remove all parts in this context. case AccumulationMode::Discard: { auto &nodes = getStorage(); - for (auto i = nodes.begin()+Offset, e = nodes.end(); i != e; ++i) + for (auto i = nodes.begin()+Offset, e = nodes.end(); i != e; ++i) { + // FIXME: This should not be needed. This breaks invariant that any + // recorded node must be a part of result souce syntax tree. if (i->isRecorded()) - getSyntaxCreator().finalizeNode(i->getOpaqueNode()); - + getRecorder().discardRecordedNode(*i); + } nodes.erase(nodes.begin()+Offset, nodes.end()); break; } diff --git a/lib/SyntaxParse/RawSyntaxTokenCache.h b/lib/SyntaxParse/RawSyntaxTokenCache.h index a200df27ed1a8..e54dcc5223e2b 100644 --- a/lib/SyntaxParse/RawSyntaxTokenCache.h +++ b/lib/SyntaxParse/RawSyntaxTokenCache.h @@ -39,7 +39,8 @@ class RawSyntaxCacheNode : public llvm::FoldingSetNode { llvm::FoldingSetNodeIDRef IDRef; public: - RawSyntaxCacheNode(RC Obj, const llvm::FoldingSetNodeIDRef IDRef) + RawSyntaxCacheNode(RC &Obj, + const llvm::FoldingSetNodeIDRef IDRef) : Obj(Obj), IDRef(IDRef) {} /// Retrieve assciated RawSyntax. diff --git a/lib/SyntaxParse/SyntaxTreeCreator.cpp b/lib/SyntaxParse/SyntaxTreeCreator.cpp index a20bf39a35a48..f5a71dd8ef25b 100644 --- a/lib/SyntaxParse/SyntaxTreeCreator.cpp +++ b/lib/SyntaxParse/SyntaxTreeCreator.cpp @@ -173,3 +173,9 @@ SyntaxTreeCreator::lookupNode(size_t lexerOffset, syntax::SyntaxKind kind) { raw.resetWithoutRelease(); return {length, opaqueN}; } + +void SyntaxTreeCreator::discardRecordedNode(OpaqueSyntaxNode opaqueN) { + if (!opaqueN) + return; + static_cast(opaqueN)->Release(); +} diff --git a/test/Syntax/serialize_tupletype.swift.result b/test/Syntax/serialize_tupletype.swift.result index d79659405b3d7..c186b51c93d6b 100644 --- a/test/Syntax/serialize_tupletype.swift.result +++ b/test/Syntax/serialize_tupletype.swift.result @@ -17,7 +17,7 @@ null, null, { - "id": 1, + "id": 33, "tokenKind": { "kind": "kw_typealias" }, @@ -48,7 +48,7 @@ "presence": "Present" }, { - "id": 2, + "id": 34, "tokenKind": { "kind": "identifier", "text": "x" @@ -64,11 +64,11 @@ }, null, { - "id": 34, + "id": 32, "kind": "TypeInitializerClause", "layout": [ { - "id": 3, + "id": 1, "tokenKind": { "kind": "equal" }, @@ -82,11 +82,11 @@ "presence": "Present" }, { - "id": 33, + "id": 31, "kind": "TupleType", "layout": [ { - "id": 20, + "id": 18, "tokenKind": { "kind": "l_paren" }, @@ -95,16 +95,16 @@ "presence": "Present" }, { - "id": 31, + "id": 29, "kind": "TupleTypeElementList", "layout": [ { - "id": 26, + "id": 24, "kind": "TupleTypeElement", "layout": [ null, { - "id": 21, + "id": 19, "tokenKind": { "kind": "identifier", "text": "b" @@ -115,7 +115,7 @@ }, null, { - "id": 22, + "id": 20, "tokenKind": { "kind": "colon" }, @@ -129,11 +129,11 @@ "presence": "Present" }, { - "id": 24, + "id": 22, "kind": "SimpleTypeIdentifier", "layout": [ { - "id": 23, + "id": 21, "tokenKind": { "kind": "identifier", "text": "Int" @@ -149,7 +149,7 @@ null, null, { - "id": 25, + "id": 23, "tokenKind": { "kind": "comma" }, @@ -166,12 +166,12 @@ "presence": "Present" }, { - "id": 30, + "id": 28, "kind": "TupleTypeElement", "layout": [ null, { - "id": 27, + "id": 25, "tokenKind": { "kind": "kw__" }, @@ -181,7 +181,7 @@ }, null, { - "id": 22, + "id": 20, "tokenKind": { "kind": "colon" }, @@ -195,11 +195,11 @@ "presence": "Present" }, { - "id": 29, + "id": 27, "kind": "SimpleTypeIdentifier", "layout": [ { - "id": 28, + "id": 26, "tokenKind": { "kind": "identifier", "text": "String" @@ -222,7 +222,7 @@ "presence": "Present" }, { - "id": 32, + "id": 30, "tokenKind": { "kind": "r_paren" }, diff --git a/tools/libSwiftSyntaxParser/libSwiftSyntaxParser.cpp b/tools/libSwiftSyntaxParser/libSwiftSyntaxParser.cpp index 898e3506d2f88..cef15dd93715f 100644 --- a/tools/libSwiftSyntaxParser/libSwiftSyntaxParser.cpp +++ b/tools/libSwiftSyntaxParser/libSwiftSyntaxParser.cpp @@ -190,6 +190,10 @@ class CLibParseActions : public SyntaxParseActions { return getNodeHandler()(&node); } + void discardRecordedNode(OpaqueSyntaxNode node) override { + // FIXME: This method should not be called at all. + } + std::pair lookupNode(size_t lexerOffset, SyntaxKind kind) override { auto NodeLookup = getNodeLookup(); From 853caa66d4496ceff53f4520c720797fb883fd95 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Tue, 17 Sep 2019 17:20:28 -0700 Subject: [PATCH 063/199] [AST] Split FileUnit and its subclasses out of Module.h Most of AST, Parse, and Sema deal with FileUnits regularly, but SIL and IRGen certainly don't. Split FileUnit out into its own header to cut down on recompilation times when something changes. No functionality change. --- include/swift/AST/FileUnit.h | 827 ++++++++++++++++++ include/swift/AST/Module.h | 809 +---------------- include/swift/ClangImporter/ClangModule.h | 2 +- include/swift/Frontend/Frontend.h | 1 + include/swift/IDE/IDERequests.h | 1 + .../Serialization/SerializedModuleLoader.h | 1 + lib/AST/ASTContext.cpp | 1 + lib/AST/ASTDumper.cpp | 1 + lib/AST/ASTMangler.cpp | 1 + lib/AST/ASTPrinter.cpp | 1 + lib/AST/ASTScope.cpp | 1 + lib/AST/ASTScopeCreation.cpp | 1 + lib/AST/ASTScopeLookup.cpp | 1 + lib/AST/ASTScopePrinting.cpp | 1 + lib/AST/ASTScopeSourceRange.cpp | 1 + lib/AST/ASTVerifier.cpp | 1 + lib/AST/AccessRequests.cpp | 1 + lib/AST/Builtins.cpp | 1 + lib/AST/ConformanceLookupTable.cpp | 1 + lib/AST/Decl.cpp | 1 + lib/AST/DeclContext.cpp | 1 + lib/AST/DiagnosticEngine.cpp | 1 + ...endenciesSourceFileDepGraphConstructor.cpp | 1 + lib/AST/GenericSignatureBuilder.cpp | 1 + lib/AST/ImportCache.cpp | 1 + lib/AST/Module.cpp | 1 + lib/AST/NameLookup.cpp | 1 + lib/AST/ProtocolConformance.cpp | 1 + lib/AST/RawComment.cpp | 1 + lib/AST/TypeRefinementContext.cpp | 1 + lib/AST/UnqualifiedLookup.cpp | 1 + lib/FrontendTool/ReferenceDependencies.cpp | 1 + lib/FrontendTool/TBD.cpp | 1 + lib/IDE/IDETypeChecking.cpp | 1 + lib/IDE/REPLCodeCompletion.cpp | 1 + lib/IDE/SourceEntityWalker.cpp | 1 + lib/IDE/SyntaxModel.cpp | 1 + lib/IRGen/IRGenModule.h | 1 + lib/Index/Index.cpp | 1 + lib/Migrator/OptionalTryMigratorPass.cpp | 1 + lib/Parse/ParseDecl.cpp | 1 + lib/Parse/ParsePattern.cpp | 1 + lib/Parse/ParseRequests.cpp | 1 + lib/Parse/Parser.cpp | 1 + lib/Parse/SyntaxParsingContext.cpp | 1 + lib/ParseSIL/ParseSIL.cpp | 1 + lib/SIL/SILProfiler.cpp | 1 + lib/SILGen/SILGenBuiltin.cpp | 1 + lib/SILGen/SILGenFunction.cpp | 1 + lib/SILGen/SILGenThunk.cpp | 1 + lib/SILGen/SILGenType.cpp | 1 + lib/Sema/CSDiagnostics.cpp | 1 + lib/Sema/DebuggerTestingTransform.cpp | 1 + lib/Sema/InstrumenterSupport.cpp | 1 + lib/Sema/LookupVisibleDecls.cpp | 1 + lib/Sema/PCMacro.cpp | 1 + lib/Sema/PlaygroundTransform.cpp | 1 + lib/Sema/ResilienceDiagnostics.cpp | 1 + lib/Sema/SourceLoader.cpp | 1 + lib/Sema/TypeAccessScopeChecker.h | 1 + lib/Sema/TypeCheckAttr.cpp | 1 + lib/Sema/TypeCheckAvailability.cpp | 1 + lib/Sema/TypeCheckDeclObjC.cpp | 1 + lib/Sema/TypeCheckExpr.cpp | 1 + lib/Sema/TypeCheckREPL.cpp | 1 + lib/Sema/TypeCheckStmt.cpp | 1 + lib/Sema/TypeCheckStorage.cpp | 1 + lib/Sema/TypeCheckType.cpp | 1 + lib/Sema/TypeChecker.cpp | 1 + lib/Serialization/ModuleFile.h | 1 + lib/Serialization/SerializeDoc.cpp | 1 + lib/SyntaxParse/SyntaxTreeCreator.cpp | 1 + lib/TBDGen/TBDGenVisitor.h | 1 + unittests/AST/TestContext.h | 1 + 74 files changed, 904 insertions(+), 805 deletions(-) create mode 100644 include/swift/AST/FileUnit.h diff --git a/include/swift/AST/FileUnit.h b/include/swift/AST/FileUnit.h new file mode 100644 index 0000000000000..a0033963170e6 --- /dev/null +++ b/include/swift/AST/FileUnit.h @@ -0,0 +1,827 @@ +//===--- FileUnit.h - The contents of a module ------------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_AST_FILEUNIT_H +#define SWIFT_AST_FILEUNIT_H + +#include "swift/AST/Module.h" + +namespace swift { +static inline unsigned alignOfFileUnit(); + +/// A container for module-scope declarations that itself provides a scope; the +/// smallest unit of code organization. +/// +/// FileUnit is an abstract base class; its subclasses represent different +/// sorts of containers that can each provide a set of decls, e.g. a source +/// file. A module can contain several file-units. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" +class FileUnit : public DeclContext { +#pragma clang diagnostic pop + virtual void anchor(); + + // FIXME: Stick this in a PointerIntPair. + const FileUnitKind Kind; + +protected: + FileUnit(FileUnitKind kind, ModuleDecl &M) + : DeclContext(DeclContextKind::FileUnit, &M), Kind(kind) { + } + +public: + FileUnitKind getKind() const { + return Kind; + } + + /// Look up a (possibly overloaded) value set at top-level scope + /// (but with the specified access path, which may come from an import decl) + /// within this file. + /// + /// This does a simple local lookup, not recursively looking through imports. + virtual void lookupValue(DeclName name, NLKind lookupKind, + SmallVectorImpl &result) const = 0; + + /// Look up a local type declaration by its mangled name. + /// + /// This does a simple local lookup, not recursively looking through imports. + virtual TypeDecl *lookupLocalType(StringRef MangledName) const { + return nullptr; + } + + /// Look up an opaque return type by the mangled name of the declaration + /// that defines it. + virtual OpaqueTypeDecl *lookupOpaqueResultType(StringRef MangledName, + LazyResolver *resolver) { + return nullptr; + } + + /// Directly look for a nested type declared within this module inside the + /// given nominal type (including any extensions). + /// + /// This is a fast-path hack to avoid circular dependencies in deserialization + /// and the Clang importer. + /// + /// Private and fileprivate types should not be returned by this lookup. + virtual TypeDecl *lookupNestedType(Identifier name, + const NominalTypeDecl *parent) const { + return nullptr; + } + + /// Find ValueDecls in the module and pass them to the given consumer object. + /// + /// This does a simple local lookup, not recursively looking through imports. + virtual void lookupVisibleDecls(ModuleDecl::AccessPathTy accessPath, + VisibleDeclConsumer &consumer, + NLKind lookupKind) const {} + + /// Finds all class members defined in this file. + /// + /// This does a simple local lookup, not recursively looking through imports. + virtual void lookupClassMembers(ModuleDecl::AccessPathTy accessPath, + VisibleDeclConsumer &consumer) const {} + + /// Finds class members defined in this file with the given name. + /// + /// This does a simple local lookup, not recursively looking through imports. + virtual void lookupClassMember(ModuleDecl::AccessPathTy accessPath, + DeclName name, + SmallVectorImpl &results) const {} + + /// Find all Objective-C methods with the given selector. + virtual void lookupObjCMethods( + ObjCSelector selector, + SmallVectorImpl &results) const = 0; + + /// Returns the comment attached to the given declaration. + /// + /// This function is an implementation detail for comment serialization. + /// If you just want to get a comment attached to a decl, use + /// \c Decl::getRawComment() or \c Decl::getBriefComment(). + virtual Optional + getCommentForDecl(const Decl *D) const { + return None; + } + + virtual Optional + getGroupNameForDecl(const Decl *D) const { + return None; + } + + virtual Optional + getSourceFileNameForDecl(const Decl *D) const { + return None; + } + + virtual Optional + getSourceOrderForDecl(const Decl *D) const { + return None; + } + + virtual Optional + getGroupNameByUSR(StringRef USR) const { + return None; + } + + virtual void collectAllGroups(std::vector &Names) const {} + + /// Returns an implementation-defined "discriminator" for \p D, which + /// distinguishes \p D from other declarations in the same module with the + /// same name. + /// + /// Since this value is used in name mangling, it should be a valid ASCII-only + /// identifier. + virtual Identifier + getDiscriminatorForPrivateValue(const ValueDecl *D) const = 0; + + /// Finds all top-level decls in this file. + /// + /// This does a simple local lookup, not recursively looking through imports. + /// The order of the results is not guaranteed to be meaningful. + virtual void getTopLevelDecls(SmallVectorImpl &results) const {} + + + /// Finds all precedence group decls in this file. + /// + /// This does a simple local lookup, not recursively looking through imports. + /// The order of the results is not guaranteed to be meaningful. + virtual void + getPrecedenceGroups(SmallVectorImpl &Results) const {} + + /// Finds all local type decls in this file. + /// + /// This does a simple local lookup, not recursively looking through imports. + /// The order of the results is not guaranteed to be meaningful. + virtual void getLocalTypeDecls(SmallVectorImpl &results) const {} + + virtual void + getOpaqueReturnTypeDecls(SmallVectorImpl &results) const {} + + /// Adds all top-level decls to the given vector. + /// + /// This includes all decls that should be displayed to clients of the module. + /// The order of the results is not guaranteed to be meaningful. + /// + /// This can differ from \c getTopLevelDecls, e.g. it returns decls from a + /// shadowed clang module. + virtual void getDisplayDecls(SmallVectorImpl &results) const { + getTopLevelDecls(results); + } + + /// Looks up which modules are imported by this file. + /// + /// \p filter controls whether public, private, or any imports are included + /// in this list. + virtual void + getImportedModules(SmallVectorImpl &imports, + ModuleDecl::ImportFilter filter) const {} + + /// \see ModuleDecl::getImportedModulesForLookup + virtual void getImportedModulesForLookup( + SmallVectorImpl &imports) const { + return getImportedModules(imports, ModuleDecl::ImportFilterKind::Public); + } + + /// Generates the list of libraries needed to link this file, based on its + /// imports. + virtual void + collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const {} + + /// True if this file contains the main class for the module. + bool hasMainClass() const { + return getMainClass(); + } + virtual ClassDecl *getMainClass() const { + assert(hasEntryPoint()); + return nullptr; + } + virtual bool hasEntryPoint() const { + return false; + } + + /// Returns the associated clang module if one exists. + virtual const clang::Module *getUnderlyingClangModule() const { + return nullptr; + } + + /// Returns the name to use when referencing entities in this file. + /// + /// Usually this is the module name itself, but certain Clang features allow + /// substituting another name instead. + virtual StringRef getExportedModuleName() const { + return getParentModule()->getName().str(); + } + + /// Traverse the decls within this file. + /// + /// \returns true if traversal was aborted, false if it completed + /// successfully. + virtual bool walk(ASTWalker &walker); + + // Efficiency override for DeclContext::getParentModule(). + ModuleDecl *getParentModule() const { + return const_cast(cast(getParent())); + } + + static bool classof(const DeclContext *DC) { + return DC->getContextKind() == DeclContextKind::FileUnit; + } + +private: + // Make placement new and vanilla new/delete illegal for FileUnits. + void *operator new(size_t Bytes) throw() = delete; + void *operator new(size_t Bytes, void *Mem) throw() = delete; + void operator delete(void *Data) throw() = delete; + +public: + // Only allow allocation of FileUnits using the allocator in ASTContext + // or by doing a placement new. + void *operator new(size_t Bytes, ASTContext &C, + unsigned Alignment = alignOfFileUnit()); +}; + +static inline unsigned alignOfFileUnit() { + return alignof(FileUnit&); +} + +/// A file containing Swift source code. +/// +/// This is a .swift or .sil file (or a virtual file, such as the contents of +/// the REPL). Since it contains raw source, it must be parsed and name-bound +/// before being used for anything; a full type-check is also necessary for +/// IR generation. +class SourceFile final : public FileUnit { +public: + class Impl; + struct SourceFileSyntaxInfo; + + /// The implicit module import that the SourceFile should get. + enum class ImplicitModuleImportKind { + None, + Builtin, + Stdlib + }; + + /// Possible attributes for imports in source files. + enum class ImportFlags { + /// The imported module is exposed to anyone who imports the parent module. + Exported = 0x1, + + /// This source file has access to testable declarations in the imported + /// module. + Testable = 0x2, + + /// This source file has access to private declarations in the imported + /// module. + PrivateImport = 0x4, + + /// The imported module is an implementation detail of this file and should + /// not be required to be present if the main module is ever imported + /// elsewhere. + /// + /// Mutually exclusive with Exported. + ImplementationOnly = 0x8 + }; + + /// \see ImportFlags + using ImportOptions = OptionSet; + + struct ImportedModuleDesc { + ModuleDecl::ImportedModule module; + ImportOptions importOptions; + StringRef filename; + + ImportedModuleDesc(ModuleDecl::ImportedModule module, ImportOptions options, + StringRef filename = {}) + : module(module), importOptions(options), filename(filename) { + assert(!(importOptions.contains(ImportFlags::Exported) && + importOptions.contains(ImportFlags::ImplementationOnly))); + } + }; + +private: + std::unique_ptr Cache; + SourceLookupCache &getCache() const; + + /// This is the list of modules that are imported by this module. + /// + /// This is filled in by the Name Binding phase. + ArrayRef Imports; + + /// A unique identifier representing this file; used to mark private decls + /// within the file to keep them from conflicting with other files in the + /// same module. + mutable Identifier PrivateDiscriminator; + + /// The root TypeRefinementContext for this SourceFile. + /// + /// This is set during type checking. + TypeRefinementContext *TRC = nullptr; + + /// If non-null, used to track name lookups that happen within this file. + Optional ReferencedNames; + + /// The class in this file marked \@NS/UIApplicationMain. + ClassDecl *MainClass = nullptr; + + /// The source location of the main class. + SourceLoc MainClassDiagLoc; + + /// A hash of all interface-contributing tokens that have been lexed for + /// this source file so far. + /// We only collect interface hash for primary input files. + llvm::Optional InterfaceHash; + + /// The ID for the memory buffer containing this file's source. + /// + /// May be -1, to indicate no association with a buffer. + int BufferID; + + /// Does this source file have any implementation-only imports? + /// If not, we can fast-path module checks. + bool HasImplementationOnlyImports = false; + + /// The scope map that describes this source file. + std::unique_ptr Scope; + + friend ASTContext; + friend Impl; +public: + /// The list of top-level declarations in the source file. + std::vector Decls; + + /// A cache of syntax nodes that can be reused when creating the syntax tree + /// for this file. + SyntaxParsingCache *SyntaxParsingCache = nullptr; + + /// The list of local type declarations in the source file. + llvm::SetVector LocalTypeDecls; + + /// The set of validated opaque return type decls in the source file. + llvm::SmallVector OpaqueReturnTypes; + llvm::StringMap ValidatedOpaqueReturnTypes; + /// The set of parsed decls with opaque return types that have not yet + /// been validated. + llvm::DenseSet UnvalidatedDeclsWithOpaqueReturnTypes; + + /// A set of special declaration attributes which require the + /// Foundation module to be imported to work. If the foundation + /// module is still not imported by the time type checking is + /// complete, we diagnose. + llvm::SetVector AttrsRequiringFoundation; + + /// A set of synthesized declarations that need to be type checked. + llvm::SmallVector SynthesizedDecls; + + /// We might perform type checking on the same source file more than once, + /// if its the main file or a REPL instance, so keep track of the last + /// checked synthesized declaration to avoid duplicating work. + unsigned LastCheckedSynthesizedDecl = 0; + + /// A mapping from Objective-C selectors to the methods that have + /// those selectors. + llvm::DenseMap> + ObjCMethods; + + /// List of Objective-C methods, which is used for checking unintended + /// Objective-C overrides. + std::vector ObjCMethodList; + + /// An unsatisfied, optional @objc requirement in a protocol conformance. + using ObjCUnsatisfiedOptReq = std::pair; + + /// List of optional @objc protocol requirements that have gone + /// unsatisfied, which might conflict with other Objective-C methods. + std::vector ObjCUnsatisfiedOptReqs; + + using ObjCMethodConflict = std::tuple; + + /// List of Objective-C member conflicts we have found during type checking. + std::vector ObjCMethodConflicts; + + template + using OperatorMap = llvm::DenseMap>; + + OperatorMap InfixOperators; + OperatorMap PostfixOperators; + OperatorMap PrefixOperators; + OperatorMap PrecedenceGroups; + + /// Describes what kind of file this is, which can affect some type checking + /// and other behavior. + const SourceFileKind Kind; + + enum ASTStage_t { + /// Parsing is underway. + Parsing, + /// Parsing has completed. + Parsed, + /// Name binding has completed. + NameBound, + /// Type checking has completed. + TypeChecked + }; + + /// Defines what phases of parsing and semantic analysis are complete for a + /// source file. + /// + /// Only files that have been fully processed (i.e. type-checked) will be + /// forwarded on to IRGen. + ASTStage_t ASTStage = Parsing; + + SourceFile(ModuleDecl &M, SourceFileKind K, Optional bufferID, + ImplicitModuleImportKind ModImpKind, bool KeepParsedTokens = false, + bool KeepSyntaxTree = false); + + ~SourceFile(); + + void addImports(ArrayRef IM); + + enum ImportQueryKind { + /// Return the results for testable or private imports. + TestableAndPrivate, + /// Return the results only for testable imports. + TestableOnly, + /// Return the results only for private imports. + PrivateOnly + }; + + bool + hasTestableOrPrivateImport(AccessLevel accessLevel, const ValueDecl *ofDecl, + ImportQueryKind kind = TestableAndPrivate) const; + + bool hasImplementationOnlyImports() const { + return HasImplementationOnlyImports; + } + + bool isImportedImplementationOnly(const ModuleDecl *module) const; + + /// This is a hack for 'main' file parsing and the integrated REPL. + /// + /// FIXME: Refactor main file parsing to not pump the parser incrementally. + /// FIXME: Remove the integrated REPL. + void clearLookupCache(); + + void cacheVisibleDecls(SmallVectorImpl &&globals) const; + const SmallVectorImpl &getCachedVisibleDecls() const; + + virtual void lookupValue(DeclName name, NLKind lookupKind, + SmallVectorImpl &result) const override; + + virtual void lookupVisibleDecls(ModuleDecl::AccessPathTy accessPath, + VisibleDeclConsumer &consumer, + NLKind lookupKind) const override; + + virtual void lookupClassMembers(ModuleDecl::AccessPathTy accessPath, + VisibleDeclConsumer &consumer) const override; + virtual void + lookupClassMember(ModuleDecl::AccessPathTy accessPath, DeclName name, + SmallVectorImpl &results) const override; + + void lookupObjCMethods( + ObjCSelector selector, + SmallVectorImpl &results) const override; + + virtual void getTopLevelDecls(SmallVectorImpl &results) const override; + + virtual void + getPrecedenceGroups(SmallVectorImpl &results) const override; + + virtual TypeDecl *lookupLocalType(llvm::StringRef MangledName) const override; + + virtual void + getLocalTypeDecls(SmallVectorImpl &results) const override; + virtual void + getOpaqueReturnTypeDecls(SmallVectorImpl &results) const override; + + virtual void + getImportedModules(SmallVectorImpl &imports, + ModuleDecl::ImportFilter filter) const override; + + virtual void + collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const override; + + Identifier getDiscriminatorForPrivateValue(const ValueDecl *D) const override; + Identifier getPrivateDiscriminator() const { return PrivateDiscriminator; } + + virtual bool walk(ASTWalker &walker) override; + + /// @{ + + /// Look up the given operator in this file. + /// + /// The file must be name-bound already. If the operator is not found, or if + /// there is an ambiguity, returns null. + /// + /// \param isCascading If true, the lookup of this operator may affect + /// downstream files. + InfixOperatorDecl *lookupInfixOperator(Identifier name, bool isCascading, + SourceLoc diagLoc = {}); + PrefixOperatorDecl *lookupPrefixOperator(Identifier name, bool isCascading, + SourceLoc diagLoc = {}); + PostfixOperatorDecl *lookupPostfixOperator(Identifier name, bool isCascading, + SourceLoc diagLoc = {}); + PrecedenceGroupDecl *lookupPrecedenceGroup(Identifier name, bool isCascading, + SourceLoc diagLoc = {}); + /// @} + + ReferencedNameTracker *getReferencedNameTracker() { + return ReferencedNames ? ReferencedNames.getPointer() : nullptr; + } + const ReferencedNameTracker *getReferencedNameTracker() const { + return ReferencedNames ? ReferencedNames.getPointer() : nullptr; + } + + void createReferencedNameTracker(); + + /// The buffer ID for the file that was imported, or None if there + /// is no associated buffer. + Optional getBufferID() const { + if (BufferID == -1) + return None; + return BufferID; + } + + /// If this buffer corresponds to a file on disk, returns the path. + /// Otherwise, return an empty string. + StringRef getFilename() const; + + /// Retrieve the scope that describes this source file. + ASTScope &getScope(); + + void dump() const; + void dump(raw_ostream &os) const; + + /// Pretty-print the contents of this source file. + /// + /// \param Printer The AST printer used for printing the contents. + /// \param PO Options controlling the printing process. + void print(ASTPrinter &Printer, const PrintOptions &PO); + void print(raw_ostream &OS, const PrintOptions &PO); + + static bool classof(const FileUnit *file) { + return file->getKind() == FileUnitKind::Source; + } + static bool classof(const DeclContext *DC) { + return isa(DC) && classof(cast(DC)); + } + + /// True if this is a "script mode" source file that admits top-level code. + bool isScriptMode() const { + switch (Kind) { + case SourceFileKind::Main: + case SourceFileKind::REPL: + return true; + + case SourceFileKind::Library: + case SourceFileKind::Interface: + case SourceFileKind::SIL: + return false; + } + llvm_unreachable("bad SourceFileKind"); + } + + ClassDecl *getMainClass() const override { + return MainClass; + } + SourceLoc getMainClassDiagLoc() const { + assert(hasMainClass()); + return MainClassDiagLoc; + } + + /// Register a "main" class for the module, complaining if there is more than + /// one. + /// + /// Should only be called during type-checking. + bool registerMainClass(ClassDecl *mainClass, SourceLoc diagLoc); + + /// True if this source file has an application entry point. + /// + /// This is true if the source file either is in script mode or contains + /// a designated main class. + bool hasEntryPoint() const override { + return isScriptMode() || hasMainClass(); + } + + /// Get the root refinement context for the file. The root context may be + /// null if the context hierarchy has not been built yet. Use + /// TypeChecker::getOrBuildTypeRefinementContext() to get a built + /// root of the hierarchy. + TypeRefinementContext *getTypeRefinementContext(); + + /// Set the root refinement context for the file. + void setTypeRefinementContext(TypeRefinementContext *TRC); + + void enableInterfaceHash() { + assert(!hasInterfaceHash()); + InterfaceHash.emplace(); + } + + bool hasInterfaceHash() const { + return InterfaceHash.hasValue(); + } + + void recordInterfaceToken(StringRef token) { + assert(!token.empty()); + InterfaceHash->update(token); + // Add null byte to separate tokens. + uint8_t a[1] = {0}; + InterfaceHash->update(a); + } + + void getInterfaceHash(llvm::SmallString<32> &str) { + llvm::MD5::MD5Result result; + InterfaceHash->final(result); + llvm::MD5::stringifyResult(result, str); + } + + void dumpInterfaceHash(llvm::raw_ostream &out) { + llvm::SmallString<32> str; + getInterfaceHash(str); + out << str << '\n'; + } + + std::vector &getTokenVector(); + + ArrayRef getAllTokens() const; + + bool shouldCollectToken() const; + + bool shouldBuildSyntaxTree() const; + + bool canBeParsedInFull() const; + + bool isSuitableForASTScopes() const { return canBeParsedInFull(); } + + syntax::SourceFileSyntax getSyntaxRoot() const; + void setSyntaxRoot(syntax::SourceFileSyntax &&Root); + bool hasSyntaxRoot() const; + + OpaqueTypeDecl *lookupOpaqueResultType(StringRef MangledName, + LazyResolver *resolver) override; + + void addUnvalidatedDeclWithOpaqueResultType(ValueDecl *vd) { + UnvalidatedDeclsWithOpaqueReturnTypes.insert(vd); + } + + void markDeclWithOpaqueResultTypeAsValidated(ValueDecl *vd); + +private: + + /// If not None, the underlying vector should contain tokens of this source file. + Optional> AllCorrectedTokens; + + std::unique_ptr SyntaxInfo; +}; + + +/// This represents the compiler's implicitly generated declarations in the +/// Builtin module. +class BuiltinUnit final : public FileUnit { +public: + class LookupCache; + +private: + std::unique_ptr Cache; + LookupCache &getCache() const; + + friend ASTContext; + ~BuiltinUnit() = default; + +public: + explicit BuiltinUnit(ModuleDecl &M); + + virtual void lookupValue(DeclName name, NLKind lookupKind, + SmallVectorImpl &result) const override; + + /// Find all Objective-C methods with the given selector. + void lookupObjCMethods( + ObjCSelector selector, + SmallVectorImpl &results) const override; + + Identifier + getDiscriminatorForPrivateValue(const ValueDecl *D) const override { + llvm_unreachable("no private values in the Builtin module"); + } + + static bool classof(const FileUnit *file) { + return file->getKind() == FileUnitKind::Builtin; + } + + static bool classof(const DeclContext *DC) { + return isa(DC) && classof(cast(DC)); + } +}; + +/// Represents an externally-loaded file of some kind. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" +class LoadedFile : public FileUnit { +#pragma clang diagnostic pop +protected: + LoadedFile(FileUnitKind Kind, ModuleDecl &M) noexcept + : FileUnit(Kind, M) { + assert(classof(this) && "invalid kind"); + } +public: + /// Returns an arbitrary string representing the storage backing this file. + /// + /// This is usually a filesystem path. + virtual StringRef getFilename() const; + + virtual StringRef getFilenameForPrivateDecl(const ValueDecl *decl) const { + return StringRef(); + } + + /// Look up an operator declaration. + /// + /// \param name The operator name ("+", ">>", etc.) + /// + /// \param fixity One of PrefixOperator, InfixOperator, or PostfixOperator. + virtual OperatorDecl *lookupOperator(Identifier name, DeclKind fixity) const { + return nullptr; + } + + /// Look up a precedence group. + /// + /// \param name The precedence group name. + virtual PrecedenceGroupDecl *lookupPrecedenceGroup(Identifier name) const { + return nullptr; + } + + /// Returns the Swift module that overlays a Clang module. + virtual ModuleDecl *getOverlayModule() const { return nullptr; } + + virtual bool isSystemModule() const { return false; } + + /// Retrieve the set of generic signatures stored within this module. + /// + /// \returns \c true if this module file supports retrieving all of the + /// generic signatures, \c false otherwise. + virtual bool getAllGenericSignatures( + SmallVectorImpl &genericSignatures) { + return false; + } + + static bool classof(const FileUnit *file) { + return file->getKind() == FileUnitKind::SerializedAST || + file->getKind() == FileUnitKind::ClangModule || + file->getKind() == FileUnitKind::DWARFModule; + } + static bool classof(const DeclContext *DC) { + return isa(DC) && classof(cast(DC)); + } +}; + + +inline SourceFile & +ModuleDecl::getMainSourceFile(SourceFileKind expectedKind) const { + assert(!Files.empty() && "No files added yet"); + assert(cast(Files.front())->Kind == expectedKind); + return *cast(Files.front()); +} + +inline FileUnit &ModuleDecl::getMainFile(FileUnitKind expectedKind) const { + assert(expectedKind != FileUnitKind::Source && + "must use specific source kind; see getMainSourceFile"); + assert(!Files.empty() && "No files added yet"); + assert(Files.front()->getKind() == expectedKind); + return *Files.front(); +} + +inline FileUnit *ModuleDecl::EntryPointInfoTy::getEntryPointFile() const { + return storage.getPointer(); +} +inline void ModuleDecl::EntryPointInfoTy::setEntryPointFile(FileUnit *file) { + assert(!storage.getPointer()); + storage.setPointer(file); +} + +inline bool ModuleDecl::EntryPointInfoTy::hasEntryPoint() const { + return storage.getPointer(); +} + +inline bool ModuleDecl::EntryPointInfoTy::markDiagnosedMultipleMainClasses() { + bool res = storage.getInt().contains(Flags::DiagnosedMultipleMainClasses); + storage.setInt(storage.getInt() | Flags::DiagnosedMultipleMainClasses); + return !res; +} + +inline bool ModuleDecl::EntryPointInfoTy::markDiagnosedMainClassWithScript() { + bool res = storage.getInt().contains(Flags::DiagnosedMainClassWithScript); + storage.setInt(storage.getInt() | Flags::DiagnosedMainClassWithScript); + return !res; +} + +} // end namespace swift + +#endif diff --git a/include/swift/AST/Module.h b/include/swift/AST/Module.h index add3ddb7a2341..801fa0caef36a 100644 --- a/include/swift/AST/Module.h +++ b/include/swift/AST/Module.h @@ -219,29 +219,12 @@ class ModuleDecl : public DeclContext, public TypeDecl { public: EntryPointInfoTy() = default; - FileUnit *getEntryPointFile() const { - return storage.getPointer(); - } - void setEntryPointFile(FileUnit *file) { - assert(!storage.getPointer()); - storage.setPointer(file); - } - - bool hasEntryPoint() const { - return storage.getPointer(); - } - - bool markDiagnosedMultipleMainClasses() { - bool res = storage.getInt().contains(Flags::DiagnosedMultipleMainClasses); - storage.setInt(storage.getInt() | Flags::DiagnosedMultipleMainClasses); - return !res; - } + FileUnit *getEntryPointFile() const; + void setEntryPointFile(FileUnit *file); + bool hasEntryPoint() const; - bool markDiagnosedMainClassWithScript() { - bool res = storage.getInt().contains(Flags::DiagnosedMainClassWithScript); - storage.setInt(storage.getInt() | Flags::DiagnosedMainClassWithScript); - return !res; - } + bool markDiagnosedMultipleMainClasses(); + bool markDiagnosedMainClassWithScript(); }; /// Information about the file responsible for the module's entry point, @@ -597,788 +580,6 @@ class ModuleDecl : public DeclContext, public TypeDecl { unsigned Alignment = alignof(ModuleDecl)); }; -static inline unsigned alignOfFileUnit(); - -/// A container for module-scope declarations that itself provides a scope; the -/// smallest unit of code organization. -/// -/// FileUnit is an abstract base class; its subclasses represent different -/// sorts of containers that can each provide a set of decls, e.g. a source -/// file. A module can contain several file-units. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wnon-virtual-dtor" -class FileUnit : public DeclContext { -#pragma clang diagnostic pop - virtual void anchor(); - - // FIXME: Stick this in a PointerIntPair. - const FileUnitKind Kind; - -protected: - FileUnit(FileUnitKind kind, ModuleDecl &M) - : DeclContext(DeclContextKind::FileUnit, &M), Kind(kind) { - } - -public: - FileUnitKind getKind() const { - return Kind; - } - - /// Look up a (possibly overloaded) value set at top-level scope - /// (but with the specified access path, which may come from an import decl) - /// within this file. - /// - /// This does a simple local lookup, not recursively looking through imports. - virtual void lookupValue(DeclName name, NLKind lookupKind, - SmallVectorImpl &result) const = 0; - - /// Look up a local type declaration by its mangled name. - /// - /// This does a simple local lookup, not recursively looking through imports. - virtual TypeDecl *lookupLocalType(StringRef MangledName) const { - return nullptr; - } - - /// Look up an opaque return type by the mangled name of the declaration - /// that defines it. - virtual OpaqueTypeDecl *lookupOpaqueResultType(StringRef MangledName, - LazyResolver *resolver) { - return nullptr; - } - - /// Directly look for a nested type declared within this module inside the - /// given nominal type (including any extensions). - /// - /// This is a fast-path hack to avoid circular dependencies in deserialization - /// and the Clang importer. - /// - /// Private and fileprivate types should not be returned by this lookup. - virtual TypeDecl *lookupNestedType(Identifier name, - const NominalTypeDecl *parent) const { - return nullptr; - } - - /// Find ValueDecls in the module and pass them to the given consumer object. - /// - /// This does a simple local lookup, not recursively looking through imports. - virtual void lookupVisibleDecls(ModuleDecl::AccessPathTy accessPath, - VisibleDeclConsumer &consumer, - NLKind lookupKind) const {} - - /// Finds all class members defined in this file. - /// - /// This does a simple local lookup, not recursively looking through imports. - virtual void lookupClassMembers(ModuleDecl::AccessPathTy accessPath, - VisibleDeclConsumer &consumer) const {} - - /// Finds class members defined in this file with the given name. - /// - /// This does a simple local lookup, not recursively looking through imports. - virtual void lookupClassMember(ModuleDecl::AccessPathTy accessPath, - DeclName name, - SmallVectorImpl &results) const {} - - /// Find all Objective-C methods with the given selector. - virtual void lookupObjCMethods( - ObjCSelector selector, - SmallVectorImpl &results) const = 0; - - /// Returns the comment attached to the given declaration. - /// - /// This function is an implementation detail for comment serialization. - /// If you just want to get a comment attached to a decl, use - /// \c Decl::getRawComment() or \c Decl::getBriefComment(). - virtual Optional - getCommentForDecl(const Decl *D) const { - return None; - } - - virtual Optional - getGroupNameForDecl(const Decl *D) const { - return None; - } - - virtual Optional - getSourceFileNameForDecl(const Decl *D) const { - return None; - } - - virtual Optional - getSourceOrderForDecl(const Decl *D) const { - return None; - } - - virtual Optional - getGroupNameByUSR(StringRef USR) const { - return None; - } - - virtual void collectAllGroups(std::vector &Names) const {} - - /// Returns an implementation-defined "discriminator" for \p D, which - /// distinguishes \p D from other declarations in the same module with the - /// same name. - /// - /// Since this value is used in name mangling, it should be a valid ASCII-only - /// identifier. - virtual Identifier - getDiscriminatorForPrivateValue(const ValueDecl *D) const = 0; - - /// Finds all top-level decls in this file. - /// - /// This does a simple local lookup, not recursively looking through imports. - /// The order of the results is not guaranteed to be meaningful. - virtual void getTopLevelDecls(SmallVectorImpl &results) const {} - - - /// Finds all precedence group decls in this file. - /// - /// This does a simple local lookup, not recursively looking through imports. - /// The order of the results is not guaranteed to be meaningful. - virtual void - getPrecedenceGroups(SmallVectorImpl &Results) const {} - - /// Finds all local type decls in this file. - /// - /// This does a simple local lookup, not recursively looking through imports. - /// The order of the results is not guaranteed to be meaningful. - virtual void getLocalTypeDecls(SmallVectorImpl &results) const {} - - virtual void - getOpaqueReturnTypeDecls(SmallVectorImpl &results) const {} - - /// Adds all top-level decls to the given vector. - /// - /// This includes all decls that should be displayed to clients of the module. - /// The order of the results is not guaranteed to be meaningful. - /// - /// This can differ from \c getTopLevelDecls, e.g. it returns decls from a - /// shadowed clang module. - virtual void getDisplayDecls(SmallVectorImpl &results) const { - getTopLevelDecls(results); - } - - /// Looks up which modules are imported by this file. - /// - /// \p filter controls whether public, private, or any imports are included - /// in this list. - virtual void - getImportedModules(SmallVectorImpl &imports, - ModuleDecl::ImportFilter filter) const {} - - /// \see ModuleDecl::getImportedModulesForLookup - virtual void getImportedModulesForLookup( - SmallVectorImpl &imports) const { - return getImportedModules(imports, ModuleDecl::ImportFilterKind::Public); - } - - /// Generates the list of libraries needed to link this file, based on its - /// imports. - virtual void - collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const {} - - /// True if this file contains the main class for the module. - bool hasMainClass() const { - return getMainClass(); - } - virtual ClassDecl *getMainClass() const { - assert(hasEntryPoint()); - return nullptr; - } - virtual bool hasEntryPoint() const { - return false; - } - - /// Returns the associated clang module if one exists. - virtual const clang::Module *getUnderlyingClangModule() const { - return nullptr; - } - - /// Returns the name to use when referencing entities in this file. - /// - /// Usually this is the module name itself, but certain Clang features allow - /// substituting another name instead. - virtual StringRef getExportedModuleName() const { - return getParentModule()->getName().str(); - } - - /// Traverse the decls within this file. - /// - /// \returns true if traversal was aborted, false if it completed - /// successfully. - virtual bool walk(ASTWalker &walker); - - // Efficiency override for DeclContext::getParentModule(). - ModuleDecl *getParentModule() const { - return const_cast(cast(getParent())); - } - - static bool classof(const DeclContext *DC) { - return DC->getContextKind() == DeclContextKind::FileUnit; - } - -private: - // Make placement new and vanilla new/delete illegal for FileUnits. - void *operator new(size_t Bytes) throw() = delete; - void *operator new(size_t Bytes, void *Mem) throw() = delete; - void operator delete(void *Data) throw() = delete; - -public: - // Only allow allocation of FileUnits using the allocator in ASTContext - // or by doing a placement new. - void *operator new(size_t Bytes, ASTContext &C, - unsigned Alignment = alignOfFileUnit()); -}; - -static inline unsigned alignOfFileUnit() { - return alignof(FileUnit&); -} - -/// A file containing Swift source code. -/// -/// This is a .swift or .sil file (or a virtual file, such as the contents of -/// the REPL). Since it contains raw source, it must be parsed and name-bound -/// before being used for anything; a full type-check is also necessary for -/// IR generation. -class SourceFile final : public FileUnit { -public: - class Impl; - struct SourceFileSyntaxInfo; - - /// The implicit module import that the SourceFile should get. - enum class ImplicitModuleImportKind { - None, - Builtin, - Stdlib - }; - - /// Possible attributes for imports in source files. - enum class ImportFlags { - /// The imported module is exposed to anyone who imports the parent module. - Exported = 0x1, - - /// This source file has access to testable declarations in the imported - /// module. - Testable = 0x2, - - /// This source file has access to private declarations in the imported - /// module. - PrivateImport = 0x4, - - /// The imported module is an implementation detail of this file and should - /// not be required to be present if the main module is ever imported - /// elsewhere. - /// - /// Mutually exclusive with Exported. - ImplementationOnly = 0x8 - }; - - /// \see ImportFlags - using ImportOptions = OptionSet; - - struct ImportedModuleDesc { - ModuleDecl::ImportedModule module; - ImportOptions importOptions; - StringRef filename; - - ImportedModuleDesc(ModuleDecl::ImportedModule module, ImportOptions options, - StringRef filename = {}) - : module(module), importOptions(options), filename(filename) { - assert(!(importOptions.contains(ImportFlags::Exported) && - importOptions.contains(ImportFlags::ImplementationOnly))); - } - }; - -private: - std::unique_ptr Cache; - SourceLookupCache &getCache() const; - - /// This is the list of modules that are imported by this module. - /// - /// This is filled in by the Name Binding phase. - ArrayRef Imports; - - /// A unique identifier representing this file; used to mark private decls - /// within the file to keep them from conflicting with other files in the - /// same module. - mutable Identifier PrivateDiscriminator; - - /// The root TypeRefinementContext for this SourceFile. - /// - /// This is set during type checking. - TypeRefinementContext *TRC = nullptr; - - /// If non-null, used to track name lookups that happen within this file. - Optional ReferencedNames; - - /// The class in this file marked \@NS/UIApplicationMain. - ClassDecl *MainClass = nullptr; - - /// The source location of the main class. - SourceLoc MainClassDiagLoc; - - /// A hash of all interface-contributing tokens that have been lexed for - /// this source file so far. - /// We only collect interface hash for primary input files. - llvm::Optional InterfaceHash; - - /// The ID for the memory buffer containing this file's source. - /// - /// May be -1, to indicate no association with a buffer. - int BufferID; - - /// Does this source file have any implementation-only imports? - /// If not, we can fast-path module checks. - bool HasImplementationOnlyImports = false; - - /// The scope map that describes this source file. - std::unique_ptr Scope; - - friend ASTContext; - friend Impl; -public: - /// The list of top-level declarations in the source file. - std::vector Decls; - - /// A cache of syntax nodes that can be reused when creating the syntax tree - /// for this file. - SyntaxParsingCache *SyntaxParsingCache = nullptr; - - /// The list of local type declarations in the source file. - llvm::SetVector LocalTypeDecls; - - /// The set of validated opaque return type decls in the source file. - llvm::SmallVector OpaqueReturnTypes; - llvm::StringMap ValidatedOpaqueReturnTypes; - /// The set of parsed decls with opaque return types that have not yet - /// been validated. - llvm::DenseSet UnvalidatedDeclsWithOpaqueReturnTypes; - - /// A set of special declaration attributes which require the - /// Foundation module to be imported to work. If the foundation - /// module is still not imported by the time type checking is - /// complete, we diagnose. - llvm::SetVector AttrsRequiringFoundation; - - /// A set of synthesized declarations that need to be type checked. - llvm::SmallVector SynthesizedDecls; - - /// We might perform type checking on the same source file more than once, - /// if its the main file or a REPL instance, so keep track of the last - /// checked synthesized declaration to avoid duplicating work. - unsigned LastCheckedSynthesizedDecl = 0; - - /// A mapping from Objective-C selectors to the methods that have - /// those selectors. - llvm::DenseMap> - ObjCMethods; - - /// List of Objective-C methods, which is used for checking unintended - /// Objective-C overrides. - std::vector ObjCMethodList; - - /// An unsatisfied, optional @objc requirement in a protocol conformance. - using ObjCUnsatisfiedOptReq = std::pair; - - /// List of optional @objc protocol requirements that have gone - /// unsatisfied, which might conflict with other Objective-C methods. - std::vector ObjCUnsatisfiedOptReqs; - - using ObjCMethodConflict = std::tuple; - - /// List of Objective-C member conflicts we have found during type checking. - std::vector ObjCMethodConflicts; - - template - using OperatorMap = llvm::DenseMap>; - - OperatorMap InfixOperators; - OperatorMap PostfixOperators; - OperatorMap PrefixOperators; - OperatorMap PrecedenceGroups; - - /// Describes what kind of file this is, which can affect some type checking - /// and other behavior. - const SourceFileKind Kind; - - enum ASTStage_t { - /// Parsing is underway. - Parsing, - /// Parsing has completed. - Parsed, - /// Name binding has completed. - NameBound, - /// Type checking has completed. - TypeChecked - }; - - /// Defines what phases of parsing and semantic analysis are complete for a - /// source file. - /// - /// Only files that have been fully processed (i.e. type-checked) will be - /// forwarded on to IRGen. - ASTStage_t ASTStage = Parsing; - - SourceFile(ModuleDecl &M, SourceFileKind K, Optional bufferID, - ImplicitModuleImportKind ModImpKind, bool KeepParsedTokens = false, - bool KeepSyntaxTree = false); - - ~SourceFile(); - - void addImports(ArrayRef IM); - - enum ImportQueryKind { - /// Return the results for testable or private imports. - TestableAndPrivate, - /// Return the results only for testable imports. - TestableOnly, - /// Return the results only for private imports. - PrivateOnly - }; - - bool - hasTestableOrPrivateImport(AccessLevel accessLevel, const ValueDecl *ofDecl, - ImportQueryKind kind = TestableAndPrivate) const; - - bool hasImplementationOnlyImports() const { - return HasImplementationOnlyImports; - } - - bool isImportedImplementationOnly(const ModuleDecl *module) const; - - /// This is a hack for 'main' file parsing and the integrated REPL. - /// - /// FIXME: Refactor main file parsing to not pump the parser incrementally. - /// FIXME: Remove the integrated REPL. - void clearLookupCache(); - - void cacheVisibleDecls(SmallVectorImpl &&globals) const; - const SmallVectorImpl &getCachedVisibleDecls() const; - - virtual void lookupValue(DeclName name, NLKind lookupKind, - SmallVectorImpl &result) const override; - - virtual void lookupVisibleDecls(ModuleDecl::AccessPathTy accessPath, - VisibleDeclConsumer &consumer, - NLKind lookupKind) const override; - - virtual void lookupClassMembers(ModuleDecl::AccessPathTy accessPath, - VisibleDeclConsumer &consumer) const override; - virtual void - lookupClassMember(ModuleDecl::AccessPathTy accessPath, DeclName name, - SmallVectorImpl &results) const override; - - void lookupObjCMethods( - ObjCSelector selector, - SmallVectorImpl &results) const override; - - virtual void getTopLevelDecls(SmallVectorImpl &results) const override; - - virtual void - getPrecedenceGroups(SmallVectorImpl &results) const override; - - virtual TypeDecl *lookupLocalType(llvm::StringRef MangledName) const override; - - virtual void - getLocalTypeDecls(SmallVectorImpl &results) const override; - virtual void - getOpaqueReturnTypeDecls(SmallVectorImpl &results) const override; - - virtual void - getImportedModules(SmallVectorImpl &imports, - ModuleDecl::ImportFilter filter) const override; - - virtual void - collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const override; - - Identifier getDiscriminatorForPrivateValue(const ValueDecl *D) const override; - Identifier getPrivateDiscriminator() const { return PrivateDiscriminator; } - - virtual bool walk(ASTWalker &walker) override; - - /// @{ - - /// Look up the given operator in this file. - /// - /// The file must be name-bound already. If the operator is not found, or if - /// there is an ambiguity, returns null. - /// - /// \param isCascading If true, the lookup of this operator may affect - /// downstream files. - InfixOperatorDecl *lookupInfixOperator(Identifier name, bool isCascading, - SourceLoc diagLoc = {}); - PrefixOperatorDecl *lookupPrefixOperator(Identifier name, bool isCascading, - SourceLoc diagLoc = {}); - PostfixOperatorDecl *lookupPostfixOperator(Identifier name, bool isCascading, - SourceLoc diagLoc = {}); - PrecedenceGroupDecl *lookupPrecedenceGroup(Identifier name, bool isCascading, - SourceLoc diagLoc = {}); - /// @} - - ReferencedNameTracker *getReferencedNameTracker() { - return ReferencedNames ? ReferencedNames.getPointer() : nullptr; - } - const ReferencedNameTracker *getReferencedNameTracker() const { - return ReferencedNames ? ReferencedNames.getPointer() : nullptr; - } - - void createReferencedNameTracker(); - - /// The buffer ID for the file that was imported, or None if there - /// is no associated buffer. - Optional getBufferID() const { - if (BufferID == -1) - return None; - return BufferID; - } - - /// If this buffer corresponds to a file on disk, returns the path. - /// Otherwise, return an empty string. - StringRef getFilename() const; - - /// Retrieve the scope that describes this source file. - ASTScope &getScope(); - - void dump() const; - void dump(raw_ostream &os) const; - - /// Pretty-print the contents of this source file. - /// - /// \param Printer The AST printer used for printing the contents. - /// \param PO Options controlling the printing process. - void print(ASTPrinter &Printer, const PrintOptions &PO); - void print(raw_ostream &OS, const PrintOptions &PO); - - static bool classof(const FileUnit *file) { - return file->getKind() == FileUnitKind::Source; - } - static bool classof(const DeclContext *DC) { - return isa(DC) && classof(cast(DC)); - } - - /// True if this is a "script mode" source file that admits top-level code. - bool isScriptMode() const { - switch (Kind) { - case SourceFileKind::Main: - case SourceFileKind::REPL: - return true; - - case SourceFileKind::Library: - case SourceFileKind::Interface: - case SourceFileKind::SIL: - return false; - } - llvm_unreachable("bad SourceFileKind"); - } - - ClassDecl *getMainClass() const override { - return MainClass; - } - SourceLoc getMainClassDiagLoc() const { - assert(hasMainClass()); - return MainClassDiagLoc; - } - - /// Register a "main" class for the module, complaining if there is more than - /// one. - /// - /// Should only be called during type-checking. - bool registerMainClass(ClassDecl *mainClass, SourceLoc diagLoc); - - /// True if this source file has an application entry point. - /// - /// This is true if the source file either is in script mode or contains - /// a designated main class. - bool hasEntryPoint() const override { - return isScriptMode() || hasMainClass(); - } - - /// Get the root refinement context for the file. The root context may be - /// null if the context hierarchy has not been built yet. Use - /// TypeChecker::getOrBuildTypeRefinementContext() to get a built - /// root of the hierarchy. - TypeRefinementContext *getTypeRefinementContext(); - - /// Set the root refinement context for the file. - void setTypeRefinementContext(TypeRefinementContext *TRC); - - void enableInterfaceHash() { - assert(!hasInterfaceHash()); - InterfaceHash.emplace(); - } - - bool hasInterfaceHash() const { - return InterfaceHash.hasValue(); - } - - void recordInterfaceToken(StringRef token) { - assert(!token.empty()); - InterfaceHash->update(token); - // Add null byte to separate tokens. - uint8_t a[1] = {0}; - InterfaceHash->update(a); - } - - void getInterfaceHash(llvm::SmallString<32> &str) { - llvm::MD5::MD5Result result; - InterfaceHash->final(result); - llvm::MD5::stringifyResult(result, str); - } - - void dumpInterfaceHash(llvm::raw_ostream &out) { - llvm::SmallString<32> str; - getInterfaceHash(str); - out << str << '\n'; - } - - std::vector &getTokenVector(); - - ArrayRef getAllTokens() const; - - bool shouldCollectToken() const; - - bool shouldBuildSyntaxTree() const; - - bool canBeParsedInFull() const; - - bool isSuitableForASTScopes() const { return canBeParsedInFull(); } - - syntax::SourceFileSyntax getSyntaxRoot() const; - void setSyntaxRoot(syntax::SourceFileSyntax &&Root); - bool hasSyntaxRoot() const; - - OpaqueTypeDecl *lookupOpaqueResultType(StringRef MangledName, - LazyResolver *resolver) override; - - void addUnvalidatedDeclWithOpaqueResultType(ValueDecl *vd) { - UnvalidatedDeclsWithOpaqueReturnTypes.insert(vd); - } - - void markDeclWithOpaqueResultTypeAsValidated(ValueDecl *vd); - -private: - - /// If not None, the underlying vector should contain tokens of this source file. - Optional> AllCorrectedTokens; - - std::unique_ptr SyntaxInfo; -}; - - -/// This represents the compiler's implicitly generated declarations in the -/// Builtin module. -class BuiltinUnit final : public FileUnit { -public: - class LookupCache; - -private: - std::unique_ptr Cache; - LookupCache &getCache() const; - - friend ASTContext; - ~BuiltinUnit() = default; - -public: - explicit BuiltinUnit(ModuleDecl &M); - - virtual void lookupValue(DeclName name, NLKind lookupKind, - SmallVectorImpl &result) const override; - - /// Find all Objective-C methods with the given selector. - void lookupObjCMethods( - ObjCSelector selector, - SmallVectorImpl &results) const override; - - Identifier - getDiscriminatorForPrivateValue(const ValueDecl *D) const override { - llvm_unreachable("no private values in the Builtin module"); - } - - static bool classof(const FileUnit *file) { - return file->getKind() == FileUnitKind::Builtin; - } - - static bool classof(const DeclContext *DC) { - return isa(DC) && classof(cast(DC)); - } -}; - -/// Represents an externally-loaded file of some kind. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wnon-virtual-dtor" -class LoadedFile : public FileUnit { -#pragma clang diagnostic pop -protected: - LoadedFile(FileUnitKind Kind, ModuleDecl &M) noexcept - : FileUnit(Kind, M) { - assert(classof(this) && "invalid kind"); - } -public: - /// Returns an arbitrary string representing the storage backing this file. - /// - /// This is usually a filesystem path. - virtual StringRef getFilename() const; - - virtual StringRef getFilenameForPrivateDecl(const ValueDecl *decl) const { - return StringRef(); - } - - /// Look up an operator declaration. - /// - /// \param name The operator name ("+", ">>", etc.) - /// - /// \param fixity One of PrefixOperator, InfixOperator, or PostfixOperator. - virtual OperatorDecl *lookupOperator(Identifier name, DeclKind fixity) const { - return nullptr; - } - - /// Look up a precedence group. - /// - /// \param name The precedence group name. - virtual PrecedenceGroupDecl *lookupPrecedenceGroup(Identifier name) const { - return nullptr; - } - - /// Returns the Swift module that overlays a Clang module. - virtual ModuleDecl *getOverlayModule() const { return nullptr; } - - virtual bool isSystemModule() const { return false; } - - /// Retrieve the set of generic signatures stored within this module. - /// - /// \returns \c true if this module file supports retrieving all of the - /// generic signatures, \c false otherwise. - virtual bool getAllGenericSignatures( - SmallVectorImpl &genericSignatures) { - return false; - } - - static bool classof(const FileUnit *file) { - return file->getKind() == FileUnitKind::SerializedAST || - file->getKind() == FileUnitKind::ClangModule || - file->getKind() == FileUnitKind::DWARFModule; - } - static bool classof(const DeclContext *DC) { - return isa(DC) && classof(cast(DC)); - } -}; - - -inline SourceFile & -ModuleDecl::getMainSourceFile(SourceFileKind expectedKind) const { - assert(!Files.empty() && "No files added yet"); - assert(cast(Files.front())->Kind == expectedKind); - return *cast(Files.front()); -} - -inline FileUnit &ModuleDecl::getMainFile(FileUnitKind expectedKind) const { - assert(expectedKind != FileUnitKind::Source && - "must use specific source kind; see getMainSourceFile"); - assert(!Files.empty() && "No files added yet"); - assert(Files.front()->getKind() == expectedKind); - return *Files.front(); -} - /// Wraps either a swift module or a clang one. /// FIXME: Should go away once swift modules can support submodules natively. class ModuleEntity { diff --git a/include/swift/ClangImporter/ClangModule.h b/include/swift/ClangImporter/ClangModule.h index 0e25a2afe1cd1..baa65c5551ebf 100644 --- a/include/swift/ClangImporter/ClangModule.h +++ b/include/swift/ClangImporter/ClangModule.h @@ -16,7 +16,7 @@ #ifndef SWIFT_CLANGIMPORTER_CLANGMODULE_H #define SWIFT_CLANGIMPORTER_CLANGMODULE_H -#include "swift/AST/Module.h" +#include "swift/AST/FileUnit.h" #include "swift/ClangImporter/ClangImporter.h" #include "clang/AST/ExternalASTSource.h" diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h index f02499381f35b..c1cff3eaf70af 100644 --- a/include/swift/Frontend/Frontend.h +++ b/include/swift/Frontend/Frontend.h @@ -20,6 +20,7 @@ #include "swift/AST/DiagnosticConsumer.h" #include "swift/AST/DiagnosticEngine.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/IRGenOptions.h" #include "swift/AST/LinkLibrary.h" #include "swift/AST/Module.h" diff --git a/include/swift/IDE/IDERequests.h b/include/swift/IDE/IDERequests.h index ef3d0ea079696..3d716384d238b 100644 --- a/include/swift/IDE/IDERequests.h +++ b/include/swift/IDE/IDERequests.h @@ -18,6 +18,7 @@ #include "swift/AST/ASTTypeIDs.h" #include "swift/AST/Evaluator.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/SimpleRequest.h" #include "swift/IDE/Utils.h" #include "swift/IDE/IDETypeIDs.h" diff --git a/include/swift/Serialization/SerializedModuleLoader.h b/include/swift/Serialization/SerializedModuleLoader.h index 908a3383ef46f..bbd904d541026 100644 --- a/include/swift/Serialization/SerializedModuleLoader.h +++ b/include/swift/Serialization/SerializedModuleLoader.h @@ -13,6 +13,7 @@ #ifndef SWIFT_SERIALIZATION_MODULELOADER_H #define SWIFT_SERIALIZATION_MODULELOADER_H +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/ModuleLoader.h" #include "llvm/Support/MemoryBuffer.h" diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index c1934f8f7d3e2..a91a322a48e86 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -22,6 +22,7 @@ #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/ExistentialLayout.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/GenericSignature.h" diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 62c8cec253ef9..e45a43ff5522a 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -17,6 +17,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/ASTPrinter.h" #include "swift/AST/ASTVisitor.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/Initializer.h" diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index ab957347f46a7..67f97e4cd6163 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -18,6 +18,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/ASTVisitor.h" #include "swift/AST/ExistentialLayout.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 93655487e66c5..fcc2a493903af 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -22,6 +22,7 @@ #include "swift/AST/Comment.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" diff --git a/lib/AST/ASTScope.cpp b/lib/AST/ASTScope.cpp index c996ed2707221..46405b0c614bb 100644 --- a/lib/AST/ASTScope.cpp +++ b/lib/AST/ASTScope.cpp @@ -19,6 +19,7 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index 7a3d4113b4103..830a9c596b889 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -20,6 +20,7 @@ #include "swift/AST/Attr.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" diff --git a/lib/AST/ASTScopeLookup.cpp b/lib/AST/ASTScopeLookup.cpp index 7db3b840963b7..f7f4a60ccd40d 100644 --- a/lib/AST/ASTScopeLookup.cpp +++ b/lib/AST/ASTScopeLookup.cpp @@ -19,6 +19,7 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" diff --git a/lib/AST/ASTScopePrinting.cpp b/lib/AST/ASTScopePrinting.cpp index e6adb04afdc2e..94690b41ba449 100644 --- a/lib/AST/ASTScopePrinting.cpp +++ b/lib/AST/ASTScopePrinting.cpp @@ -19,6 +19,7 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" diff --git a/lib/AST/ASTScopeSourceRange.cpp b/lib/AST/ASTScopeSourceRange.cpp index 47d5fb869dd6d..9008c20176a10 100644 --- a/lib/AST/ASTScopeSourceRange.cpp +++ b/lib/AST/ASTScopeSourceRange.cpp @@ -19,6 +19,7 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp index 96f3a1a106463..5c9f7c2ceccd3 100644 --- a/lib/AST/ASTVerifier.cpp +++ b/lib/AST/ASTVerifier.cpp @@ -20,6 +20,7 @@ #include "swift/AST/Decl.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/Expr.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/GenericSignature.h" diff --git a/lib/AST/AccessRequests.cpp b/lib/AST/AccessRequests.cpp index 0a20c266bf755..9068a787f8abb 100644 --- a/lib/AST/AccessRequests.cpp +++ b/lib/AST/AccessRequests.cpp @@ -15,6 +15,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "swift/AST/DiagnosticsCommon.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookupRequests.h" #include "swift/AST/Types.h" diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index beb25d4bf6c1b..23dc521743270 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -16,6 +16,7 @@ #include "swift/AST/Builtins.h" #include "swift/AST/ASTContext.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" diff --git a/lib/AST/ConformanceLookupTable.cpp b/lib/AST/ConformanceLookupTable.cpp index 064cf632a393e..bb98d604d569f 100644 --- a/lib/AST/ConformanceLookupTable.cpp +++ b/lib/AST/ConformanceLookupTable.cpp @@ -18,6 +18,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "swift/AST/ExistentialLayout.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 26e605bccc5bc..4d7c01be751f3 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -23,6 +23,7 @@ #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/Expr.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/GenericSignature.h" diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index e27d14d21021e..321251aba600d 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -15,6 +15,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/Expr.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" diff --git a/lib/AST/DiagnosticEngine.cpp b/lib/AST/DiagnosticEngine.cpp index d6dc1696a17f2..9b402b40a2b35 100644 --- a/lib/AST/DiagnosticEngine.cpp +++ b/lib/AST/DiagnosticEngine.cpp @@ -20,6 +20,7 @@ #include "swift/AST/ASTPrinter.h" #include "swift/AST/Decl.h" #include "swift/AST/DiagnosticSuppression.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/Pattern.h" #include "swift/AST/PrintOptions.h" diff --git a/lib/AST/ExperimentalDependenciesSourceFileDepGraphConstructor.cpp b/lib/AST/ExperimentalDependenciesSourceFileDepGraphConstructor.cpp index 3987a603312aa..8986edfdad3b5 100644 --- a/lib/AST/ExperimentalDependenciesSourceFileDepGraphConstructor.cpp +++ b/lib/AST/ExperimentalDependenciesSourceFileDepGraphConstructor.cpp @@ -21,6 +21,7 @@ #include "swift/AST/ExistentialLayout.h" #include "swift/AST/ExperimentalDependencies.h" #include "swift/AST/FileSystem.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/ModuleLoader.h" #include "swift/AST/NameLookup.h" diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp index ea2536b296ea8..d03fa68c278bf 100644 --- a/lib/AST/GenericSignatureBuilder.cpp +++ b/lib/AST/GenericSignatureBuilder.cpp @@ -22,6 +22,7 @@ #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/ExistentialLayout.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" diff --git a/lib/AST/ImportCache.cpp b/lib/AST/ImportCache.cpp index 4e4b6676a9056..2d8ff08890c96 100644 --- a/lib/AST/ImportCache.cpp +++ b/lib/AST/ImportCache.cpp @@ -18,6 +18,7 @@ #include "llvm/ADT/DenseSet.h" #include "swift/AST/ASTContext.h" #include "swift/AST/ClangModuleLoader.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/ImportCache.h" #include "swift/AST/Module.h" diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 3378423f291d9..1c28f6ef5f2ea 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -23,6 +23,7 @@ #include "swift/AST/Builtins.h" #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/ExistentialLayout.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/ImportCache.h" #include "swift/AST/LazyResolver.h" diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index 4e04d2f64f3d3..e4b9660a6056a 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -20,6 +20,7 @@ #include "swift/AST/ClangModuleLoader.h" #include "swift/AST/DebuggerClient.h" #include "swift/AST/ExistentialLayout.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/ImportCache.h" #include "swift/AST/Initializer.h" diff --git a/lib/AST/ProtocolConformance.cpp b/lib/AST/ProtocolConformance.cpp index 82a6ea1396799..e96a93bc70d18 100644 --- a/lib/AST/ProtocolConformance.cpp +++ b/lib/AST/ProtocolConformance.cpp @@ -18,6 +18,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/Availability.h" #include "swift/AST/Decl.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/Module.h" diff --git a/lib/AST/RawComment.cpp b/lib/AST/RawComment.cpp index 41815a47993f7..f60efcf4e97e2 100644 --- a/lib/AST/RawComment.cpp +++ b/lib/AST/RawComment.cpp @@ -19,6 +19,7 @@ #include "swift/AST/Comment.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/Types.h" diff --git a/lib/AST/TypeRefinementContext.cpp b/lib/AST/TypeRefinementContext.cpp index e794daf155e5d..012a66734ebc6 100644 --- a/lib/AST/TypeRefinementContext.cpp +++ b/lib/AST/TypeRefinementContext.cpp @@ -16,6 +16,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/Stmt.h" #include "swift/AST/Expr.h" diff --git a/lib/AST/UnqualifiedLookup.cpp b/lib/AST/UnqualifiedLookup.cpp index d8bd21798f606..8649e9ac991cb 100644 --- a/lib/AST/UnqualifiedLookup.cpp +++ b/lib/AST/UnqualifiedLookup.cpp @@ -20,6 +20,7 @@ #include "swift/AST/ClangModuleLoader.h" #include "swift/AST/DebuggerClient.h" #include "swift/AST/ExistentialLayout.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/ImportCache.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" diff --git a/lib/FrontendTool/ReferenceDependencies.cpp b/lib/FrontendTool/ReferenceDependencies.cpp index 6c73f563b646d..22d114526ecd7 100644 --- a/lib/FrontendTool/ReferenceDependencies.cpp +++ b/lib/FrontendTool/ReferenceDependencies.cpp @@ -18,6 +18,7 @@ #include "swift/AST/DiagnosticsFrontend.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/FileSystem.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/ModuleLoader.h" #include "swift/AST/NameLookup.h" diff --git a/lib/FrontendTool/TBD.cpp b/lib/FrontendTool/TBD.cpp index 41726d9d28109..b80537a24e95b 100644 --- a/lib/FrontendTool/TBD.cpp +++ b/lib/FrontendTool/TBD.cpp @@ -15,6 +15,7 @@ #include "swift/AST/Decl.h" #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/DiagnosticsFrontend.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/Basic/LLVM.h" #include "swift/Demangling/Demangle.h" diff --git a/lib/IDE/IDETypeChecking.cpp b/lib/IDE/IDETypeChecking.cpp index 8459f58e2382e..2b986a742dfd1 100644 --- a/lib/IDE/IDETypeChecking.cpp +++ b/lib/IDE/IDETypeChecking.cpp @@ -18,6 +18,7 @@ #include "swift/AST/Types.h" #include "swift/AST/Attr.h" #include "swift/AST/Expr.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" diff --git a/lib/IDE/REPLCodeCompletion.cpp b/lib/IDE/REPLCodeCompletion.cpp index 6fd2d7873bb26..eb3e9f43672d9 100644 --- a/lib/IDE/REPLCodeCompletion.cpp +++ b/lib/IDE/REPLCodeCompletion.cpp @@ -17,6 +17,7 @@ #include "swift/IDE/REPLCodeCompletion.h" #include "swift/AST/ASTContext.h" #include "swift/AST/DiagnosticSuppression.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/Basic/LLVM.h" #include "swift/Basic/SourceManager.h" diff --git a/lib/IDE/SourceEntityWalker.cpp b/lib/IDE/SourceEntityWalker.cpp index cdb965e29adfd..5a4570a9af022 100644 --- a/lib/IDE/SourceEntityWalker.cpp +++ b/lib/IDE/SourceEntityWalker.cpp @@ -16,6 +16,7 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/Pattern.h" #include "swift/AST/ParameterList.h" diff --git a/lib/IDE/SyntaxModel.cpp b/lib/IDE/SyntaxModel.cpp index 19439a78fe6c9..a629842c0c136 100644 --- a/lib/IDE/SyntaxModel.cpp +++ b/lib/IDE/SyntaxModel.cpp @@ -15,6 +15,7 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Pattern.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Module.h" diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index b571cedde1238..93fc4172b395b 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -21,6 +21,7 @@ #include "IRGen.h" #include "SwiftTargetInfo.h" #include "swift/AST/Decl.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/ReferenceCounting.h" #include "swift/Basic/ClusteredBitVector.h" diff --git a/lib/Index/Index.cpp b/lib/Index/Index.cpp index 5c21b602553f3..2fe34cbf1874f 100644 --- a/lib/Index/Index.cpp +++ b/lib/Index/Index.cpp @@ -16,6 +16,7 @@ #include "swift/AST/Comment.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" #include "swift/AST/ProtocolConformance.h" diff --git a/lib/Migrator/OptionalTryMigratorPass.cpp b/lib/Migrator/OptionalTryMigratorPass.cpp index 4767f7f12cb75..d4620b43a3f00 100644 --- a/lib/Migrator/OptionalTryMigratorPass.cpp +++ b/lib/Migrator/OptionalTryMigratorPass.cpp @@ -12,6 +12,7 @@ #include "swift/AST/ASTVisitor.h" #include "swift/AST/Expr.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ParameterList.h" diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 599d3ee5b6c6f..726e817d0c3cd 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -26,6 +26,7 @@ #include "swift/AST/DebuggerClient.h" #include "swift/AST/DiagnosticsParse.h" #include "swift/AST/Initializer.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" #include "swift/AST/ParseRequests.h" diff --git a/lib/Parse/ParsePattern.cpp b/lib/Parse/ParsePattern.cpp index 9cb81c42d6ee4..e7461149276cd 100644 --- a/lib/Parse/ParsePattern.cpp +++ b/lib/Parse/ParsePattern.cpp @@ -18,6 +18,7 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/Initializer.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/Basic/StringExtras.h" #include "swift/Parse/CodeCompletionCallbacks.h" diff --git a/lib/Parse/ParseRequests.cpp b/lib/Parse/ParseRequests.cpp index f0fc0ed2568c2..0ee4fffcd831d 100644 --- a/lib/Parse/ParseRequests.cpp +++ b/lib/Parse/ParseRequests.cpp @@ -17,6 +17,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "swift/AST/DeclContext.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/Parse/Parser.h" #include "swift/Subsystems.h" diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 62783da44f29c..02ea50cde22cd 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -18,6 +18,7 @@ #include "swift/Subsystems.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/DiagnosticsParse.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/Basic/Defer.h" diff --git a/lib/Parse/SyntaxParsingContext.cpp b/lib/Parse/SyntaxParsingContext.cpp index afe5298d8a095..5f1473ac880c7 100644 --- a/lib/Parse/SyntaxParsingContext.cpp +++ b/lib/Parse/SyntaxParsingContext.cpp @@ -15,6 +15,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/DiagnosticsParse.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/Basic/Defer.h" #include "swift/Parse/ParsedSyntax.h" diff --git a/lib/ParseSIL/ParseSIL.cpp b/lib/ParseSIL/ParseSIL.cpp index b752f1433a27f..acec522fffbdb 100644 --- a/lib/ParseSIL/ParseSIL.cpp +++ b/lib/ParseSIL/ParseSIL.cpp @@ -13,6 +13,7 @@ #include "SILParserFunctionBuilder.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/ExistentialLayout.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ProtocolConformance.h" diff --git a/lib/SIL/SILProfiler.cpp b/lib/SIL/SILProfiler.cpp index 3120ddabe2e5f..8af1fe45d8c3a 100644 --- a/lib/SIL/SILProfiler.cpp +++ b/lib/SIL/SILProfiler.cpp @@ -14,6 +14,7 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/Stmt.h" #include "swift/Parse/Lexer.h" diff --git a/lib/SILGen/SILGenBuiltin.cpp b/lib/SILGen/SILGenBuiltin.cpp index 93fef79f6b362..31390a0b9838e 100644 --- a/lib/SILGen/SILGenBuiltin.cpp +++ b/lib/SILGen/SILGenBuiltin.cpp @@ -22,6 +22,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/Builtins.h" #include "swift/AST/DiagnosticsSIL.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/Module.h" #include "swift/AST/ReferenceCounting.h" diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index 015aefa47928f..f8e73177f9915 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -20,6 +20,7 @@ #include "SILGenFunctionBuilder.h" #include "Scope.h" #include "swift/AST/ClangModuleLoader.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Initializer.h" #include "swift/AST/PropertyWrappers.h" #include "swift/SIL/SILArgument.h" diff --git a/lib/SILGen/SILGenThunk.cpp b/lib/SILGen/SILGenThunk.cpp index bb631d9b48c49..42083253d28c0 100644 --- a/lib/SILGen/SILGenThunk.cpp +++ b/lib/SILGen/SILGenThunk.cpp @@ -26,6 +26,7 @@ #include "Scope.h" #include "swift/AST/ASTMangler.h" #include "swift/AST/DiagnosticsSIL.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" #include "swift/SIL/PrettyStackTrace.h" #include "swift/SIL/SILArgument.h" diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp index 9a8179e8e08a1..f02bfac7b3efd 100644 --- a/lib/SILGen/SILGenType.cpp +++ b/lib/SILGen/SILGenType.cpp @@ -22,6 +22,7 @@ #include "SILGenFunctionBuilder.h" #include "Scope.h" #include "swift/AST/ASTMangler.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/PrettyStackTrace.h" diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 4f44989f0ceb5..4399e3ea9c4a5 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -22,6 +22,7 @@ #include "swift/AST/Decl.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/Expr.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/Initializer.h" #include "swift/AST/ParameterList.h" diff --git a/lib/Sema/DebuggerTestingTransform.cpp b/lib/Sema/DebuggerTestingTransform.cpp index 70e1713c21e6b..415cfa97e8a20 100644 --- a/lib/Sema/DebuggerTestingTransform.cpp +++ b/lib/Sema/DebuggerTestingTransform.cpp @@ -21,6 +21,7 @@ #include "swift/AST/Decl.h" #include "swift/AST/DeclContext.h" #include "swift/AST/Expr.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Stmt.h" diff --git a/lib/Sema/InstrumenterSupport.cpp b/lib/Sema/InstrumenterSupport.cpp index 79dabab5810b6..52663685e0429 100644 --- a/lib/Sema/InstrumenterSupport.cpp +++ b/lib/Sema/InstrumenterSupport.cpp @@ -17,6 +17,7 @@ #include "InstrumenterSupport.h" #include "swift/AST/DiagnosticSuppression.h" +#include "swift/AST/FileUnit.h" #include "swift/Demangling/Punycode.h" #include "llvm/Support/Path.h" diff --git a/lib/Sema/LookupVisibleDecls.cpp b/lib/Sema/LookupVisibleDecls.cpp index 3af0f935ed041..2958ec8aadeb0 100644 --- a/lib/Sema/LookupVisibleDecls.cpp +++ b/lib/Sema/LookupVisibleDecls.cpp @@ -16,6 +16,7 @@ //===----------------------------------------------------------------------===// #include "swift/AST/ASTContext.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/GenericSignatureBuilder.h" #include "swift/AST/ImportCache.h" diff --git a/lib/Sema/PCMacro.cpp b/lib/Sema/PCMacro.cpp index 656fa70bbaedf..f5686ab1c4319 100644 --- a/lib/Sema/PCMacro.cpp +++ b/lib/Sema/PCMacro.cpp @@ -22,6 +22,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Module.h" #include "swift/AST/Pattern.h" diff --git a/lib/Sema/PlaygroundTransform.cpp b/lib/Sema/PlaygroundTransform.cpp index 3805491d24c5e..55e53c3c429be 100644 --- a/lib/Sema/PlaygroundTransform.cpp +++ b/lib/Sema/PlaygroundTransform.cpp @@ -20,6 +20,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "swift/AST/DeclContext.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/Pattern.h" diff --git a/lib/Sema/ResilienceDiagnostics.cpp b/lib/Sema/ResilienceDiagnostics.cpp index 5afac83616be2..42170257bdb77 100644 --- a/lib/Sema/ResilienceDiagnostics.cpp +++ b/lib/Sema/ResilienceDiagnostics.cpp @@ -19,6 +19,7 @@ #include "swift/AST/Attr.h" #include "swift/AST/Decl.h" #include "swift/AST/DeclContext.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Initializer.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/TypeDeclFinder.h" diff --git a/lib/Sema/SourceLoader.cpp b/lib/Sema/SourceLoader.cpp index 9abce488f8a2f..e9d41823c1ee5 100644 --- a/lib/Sema/SourceLoader.cpp +++ b/lib/Sema/SourceLoader.cpp @@ -19,6 +19,7 @@ #include "swift/Subsystems.h" #include "swift/AST/ASTContext.h" #include "swift/AST/DiagnosticsSema.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/Parse/PersistentParserState.h" #include "swift/Basic/SourceManager.h" diff --git a/lib/Sema/TypeAccessScopeChecker.h b/lib/Sema/TypeAccessScopeChecker.h index 767b5022afad7..5966dee3f2372 100644 --- a/lib/Sema/TypeAccessScopeChecker.h +++ b/lib/Sema/TypeAccessScopeChecker.h @@ -15,6 +15,7 @@ #include "swift/AST/Decl.h" #include "swift/AST/DeclContext.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Type.h" #include "swift/AST/TypeDeclFinder.h" #include "swift/AST/TypeRepr.h" diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 662fb95a854fa..aa5f90eb7e238 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -21,6 +21,7 @@ #include "swift/AST/ASTVisitor.h" #include "swift/AST/ClangModuleLoader.h" #include "swift/AST/DiagnosticsParse.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/GenericSignatureBuilder.h" #include "swift/AST/ModuleNameLookup.h" diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp index bdfd2d6925e0c..e7ecee8cd3a3d 100644 --- a/lib/Sema/TypeCheckAvailability.cpp +++ b/lib/Sema/TypeCheckAvailability.cpp @@ -19,6 +19,7 @@ #include "TypeCheckObjC.h" #include "MiscDiagnostics.h" #include "swift/AST/ASTWalker.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Initializer.h" #include "swift/AST/NameLookup.h" #include "swift/AST/Pattern.h" diff --git a/lib/Sema/TypeCheckDeclObjC.cpp b/lib/Sema/TypeCheckDeclObjC.cpp index 66cc11d8ea4bc..708257c632981 100644 --- a/lib/Sema/TypeCheckDeclObjC.cpp +++ b/lib/Sema/TypeCheckDeclObjC.cpp @@ -20,6 +20,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "swift/AST/ExistentialLayout.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/ImportCache.h" #include "swift/AST/ParameterList.h" diff --git a/lib/Sema/TypeCheckExpr.cpp b/lib/Sema/TypeCheckExpr.cpp index 46a925e34b2d6..d0e0787e9080a 100644 --- a/lib/Sema/TypeCheckExpr.cpp +++ b/lib/Sema/TypeCheckExpr.cpp @@ -18,6 +18,7 @@ #include "TypeChecker.h" #include "swift/AST/NameLookup.h" #include "swift/AST/Decl.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Initializer.h" #include "swift/AST/ParameterList.h" #include "swift/AST/TypeCheckRequests.h" diff --git a/lib/Sema/TypeCheckREPL.cpp b/lib/Sema/TypeCheckREPL.cpp index 5b17866ce853e..b3f35d55bbaad 100644 --- a/lib/Sema/TypeCheckREPL.cpp +++ b/lib/Sema/TypeCheckREPL.cpp @@ -19,6 +19,7 @@ #include "swift/AST/ASTVisitor.h" #include "swift/AST/DiagnosticsFrontend.h" #include "swift/AST/Expr.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Stmt.h" diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index d78ed0cb05e1d..cd16844981489 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -25,6 +25,7 @@ #include "swift/AST/ASTVisitor.h" #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/DiagnosticSuppression.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Identifier.h" #include "swift/AST/Initializer.h" #include "swift/AST/NameLookup.h" diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index 4cd1d2ecb4a20..56d89e81861ba 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -24,6 +24,7 @@ #include "swift/AST/DiagnosticsParse.h" #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/Expr.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/Initializer.h" #include "swift/AST/ParameterList.h" diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index abe05c5118fd8..0dc0679213643 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -27,6 +27,7 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/DiagnosticsParse.h" #include "swift/AST/ExistentialLayout.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/GenericSignatureBuilder.h" diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp index ff034d3ff522f..9834c4ee09261 100644 --- a/lib/Sema/TypeChecker.cpp +++ b/lib/Sema/TypeChecker.cpp @@ -26,6 +26,7 @@ #include "swift/AST/Attr.h" #include "swift/AST/DiagnosticSuppression.h" #include "swift/AST/ExistentialLayout.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Identifier.h" #include "swift/AST/ImportCache.h" #include "swift/AST/Initializer.h" diff --git a/lib/Serialization/ModuleFile.h b/lib/Serialization/ModuleFile.h index 5dce4c9b0d39b..2d532e66300b6 100644 --- a/lib/Serialization/ModuleFile.h +++ b/lib/Serialization/ModuleFile.h @@ -17,6 +17,7 @@ #include "swift/AST/Identifier.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/LinkLibrary.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/RawComment.h" #include "swift/AST/TypeLoc.h" diff --git a/lib/Serialization/SerializeDoc.cpp b/lib/Serialization/SerializeDoc.cpp index e37aff3235ffe..cd5cd5e9c99f4 100644 --- a/lib/Serialization/SerializeDoc.cpp +++ b/lib/Serialization/SerializeDoc.cpp @@ -16,6 +16,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/DiagnosticsCommon.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" #include "swift/AST/USRGeneration.h" diff --git a/lib/SyntaxParse/SyntaxTreeCreator.cpp b/lib/SyntaxParse/SyntaxTreeCreator.cpp index a20bf39a35a48..d9f7dc253b7a3 100644 --- a/lib/SyntaxParse/SyntaxTreeCreator.cpp +++ b/lib/SyntaxParse/SyntaxTreeCreator.cpp @@ -19,6 +19,7 @@ #include "swift/Parse/Token.h" #include "swift/AST/ASTContext.h" #include "swift/AST/DiagnosticsParse.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/Basic/OwnedString.h" #include "RawSyntaxTokenCache.h" diff --git a/lib/TBDGen/TBDGenVisitor.h b/lib/TBDGen/TBDGenVisitor.h index 136a8434bc4c2..5453322f810da 100644 --- a/lib/TBDGen/TBDGenVisitor.h +++ b/lib/TBDGen/TBDGenVisitor.h @@ -18,6 +18,7 @@ #include "swift/AST/ASTMangler.h" #include "swift/AST/ASTVisitor.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" #include "swift/Basic/LLVM.h" diff --git a/unittests/AST/TestContext.h b/unittests/AST/TestContext.h index f39d22307eaa4..db2625a0d8dab 100644 --- a/unittests/AST/TestContext.h +++ b/unittests/AST/TestContext.h @@ -12,6 +12,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/DiagnosticEngine.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/Basic/LangOptions.h" #include "swift/Basic/SourceManager.h" From 8d7f1b7c5ddec568ac621610379bfff1daf118e6 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Tue, 17 Sep 2019 17:50:11 -0700 Subject: [PATCH 064/199] [AST] Separate SourceFile from FileUnit.h Like the last commit, SourceFile is used a lot by Parse and Sema, but less so by the ClangImporter and (de)Serialization. Split it out to cut down on recompilation times when something changes. This commit does /not/ split the implementation of SourceFile out of Module.cpp, which is where most of it lives. That might also be a reasonable change, but the reason I was reluctant to is because a number of SourceFile members correspond to the entry points in ModuleDecl. Someone else can pick this up later if they decide it's a good idea. No functionality change. --- include/swift/AST/FileUnit.h | 462 ----------------- include/swift/AST/SourceFile.h | 483 ++++++++++++++++++ include/swift/Frontend/Frontend.h | 2 +- include/swift/IDE/IDERequests.h | 2 +- include/swift/Migrator/ASTMigratorPass.h | 1 + lib/AST/ASTContext.cpp | 1 + lib/AST/ASTDumper.cpp | 2 +- lib/AST/ASTScope.cpp | 2 +- lib/AST/ASTScopeCreation.cpp | 2 +- lib/AST/ASTScopeLookup.cpp | 2 +- lib/AST/ASTScopePrinting.cpp | 2 +- lib/AST/ASTScopeSourceRange.cpp | 2 +- lib/AST/ASTVerifier.cpp | 2 +- lib/AST/AccessRequests.cpp | 2 +- lib/AST/ConformanceLookupTable.cpp | 2 +- lib/AST/Decl.cpp | 2 +- lib/AST/DeclContext.cpp | 1 + lib/AST/DiagnosticEngine.cpp | 2 +- ...endenciesSourceFileDepGraphConstructor.cpp | 2 +- lib/AST/Module.cpp | 1 + lib/AST/NameLookup.cpp | 2 +- lib/AST/TypeRefinementContext.cpp | 2 +- lib/AST/UnqualifiedLookup.cpp | 2 +- lib/FrontendTool/ReferenceDependencies.cpp | 2 +- lib/IDE/CodeCompletion.cpp | 1 + lib/IDE/IDETypeChecking.cpp | 12 +- lib/IDE/ModuleInterfacePrinting.cpp | 1 + lib/IDE/REPLCodeCompletion.cpp | 2 +- lib/IDE/SourceEntityWalker.cpp | 2 +- lib/IDE/SyntaxModel.cpp | 2 +- lib/IRGen/IRGenModule.h | 2 +- lib/Index/Index.cpp | 2 +- lib/Index/IndexRecord.cpp | 5 +- lib/Parse/ParseDecl.cpp | 2 +- lib/Parse/ParsePattern.cpp | 2 +- lib/Parse/ParseRequests.cpp | 2 +- lib/Parse/Parser.cpp | 2 +- lib/Parse/SyntaxParsingContext.cpp | 2 +- lib/ParseSIL/ParseSIL.cpp | 2 +- lib/SIL/SILProfiler.cpp | 2 +- lib/SILGen/SILGen.cpp | 1 + lib/SILGen/SILGenType.cpp | 2 +- lib/Sema/CSDiagnostics.cpp | 2 +- lib/Sema/CodeSynthesis.cpp | 1 + lib/Sema/DebuggerTestingTransform.cpp | 2 +- lib/Sema/InstrumenterSupport.cpp | 2 +- lib/Sema/LookupVisibleDecls.cpp | 2 +- lib/Sema/NameBinding.cpp | 1 + lib/Sema/PCMacro.cpp | 2 +- lib/Sema/PlaygroundTransform.cpp | 2 +- lib/Sema/ResilienceDiagnostics.cpp | 2 +- lib/Sema/SourceLoader.cpp | 2 +- lib/Sema/TypeAccessScopeChecker.h | 2 +- lib/Sema/TypeCheckAttr.cpp | 2 +- lib/Sema/TypeCheckAvailability.cpp | 2 +- lib/Sema/TypeCheckDecl.cpp | 1 + lib/Sema/TypeCheckDeclObjC.cpp | 2 +- lib/Sema/TypeCheckExpr.cpp | 2 +- lib/Sema/TypeCheckREPL.cpp | 2 +- lib/Sema/TypeCheckStmt.cpp | 2 +- lib/Sema/TypeCheckStorage.cpp | 2 +- lib/Sema/TypeCheckType.cpp | 2 +- lib/Sema/TypeChecker.cpp | 2 +- lib/Serialization/Serialization.cpp | 1 + lib/Serialization/SerializeDoc.cpp | 2 +- lib/SyntaxParse/SyntaxTreeCreator.cpp | 2 +- unittests/AST/TestContext.h | 2 +- 67 files changed, 555 insertions(+), 522 deletions(-) create mode 100644 include/swift/AST/SourceFile.h diff --git a/include/swift/AST/FileUnit.h b/include/swift/AST/FileUnit.h index a0033963170e6..388c46446fd2e 100644 --- a/include/swift/AST/FileUnit.h +++ b/include/swift/AST/FileUnit.h @@ -253,437 +253,6 @@ static inline unsigned alignOfFileUnit() { return alignof(FileUnit&); } -/// A file containing Swift source code. -/// -/// This is a .swift or .sil file (or a virtual file, such as the contents of -/// the REPL). Since it contains raw source, it must be parsed and name-bound -/// before being used for anything; a full type-check is also necessary for -/// IR generation. -class SourceFile final : public FileUnit { -public: - class Impl; - struct SourceFileSyntaxInfo; - - /// The implicit module import that the SourceFile should get. - enum class ImplicitModuleImportKind { - None, - Builtin, - Stdlib - }; - - /// Possible attributes for imports in source files. - enum class ImportFlags { - /// The imported module is exposed to anyone who imports the parent module. - Exported = 0x1, - - /// This source file has access to testable declarations in the imported - /// module. - Testable = 0x2, - - /// This source file has access to private declarations in the imported - /// module. - PrivateImport = 0x4, - - /// The imported module is an implementation detail of this file and should - /// not be required to be present if the main module is ever imported - /// elsewhere. - /// - /// Mutually exclusive with Exported. - ImplementationOnly = 0x8 - }; - - /// \see ImportFlags - using ImportOptions = OptionSet; - - struct ImportedModuleDesc { - ModuleDecl::ImportedModule module; - ImportOptions importOptions; - StringRef filename; - - ImportedModuleDesc(ModuleDecl::ImportedModule module, ImportOptions options, - StringRef filename = {}) - : module(module), importOptions(options), filename(filename) { - assert(!(importOptions.contains(ImportFlags::Exported) && - importOptions.contains(ImportFlags::ImplementationOnly))); - } - }; - -private: - std::unique_ptr Cache; - SourceLookupCache &getCache() const; - - /// This is the list of modules that are imported by this module. - /// - /// This is filled in by the Name Binding phase. - ArrayRef Imports; - - /// A unique identifier representing this file; used to mark private decls - /// within the file to keep them from conflicting with other files in the - /// same module. - mutable Identifier PrivateDiscriminator; - - /// The root TypeRefinementContext for this SourceFile. - /// - /// This is set during type checking. - TypeRefinementContext *TRC = nullptr; - - /// If non-null, used to track name lookups that happen within this file. - Optional ReferencedNames; - - /// The class in this file marked \@NS/UIApplicationMain. - ClassDecl *MainClass = nullptr; - - /// The source location of the main class. - SourceLoc MainClassDiagLoc; - - /// A hash of all interface-contributing tokens that have been lexed for - /// this source file so far. - /// We only collect interface hash for primary input files. - llvm::Optional InterfaceHash; - - /// The ID for the memory buffer containing this file's source. - /// - /// May be -1, to indicate no association with a buffer. - int BufferID; - - /// Does this source file have any implementation-only imports? - /// If not, we can fast-path module checks. - bool HasImplementationOnlyImports = false; - - /// The scope map that describes this source file. - std::unique_ptr Scope; - - friend ASTContext; - friend Impl; -public: - /// The list of top-level declarations in the source file. - std::vector Decls; - - /// A cache of syntax nodes that can be reused when creating the syntax tree - /// for this file. - SyntaxParsingCache *SyntaxParsingCache = nullptr; - - /// The list of local type declarations in the source file. - llvm::SetVector LocalTypeDecls; - - /// The set of validated opaque return type decls in the source file. - llvm::SmallVector OpaqueReturnTypes; - llvm::StringMap ValidatedOpaqueReturnTypes; - /// The set of parsed decls with opaque return types that have not yet - /// been validated. - llvm::DenseSet UnvalidatedDeclsWithOpaqueReturnTypes; - - /// A set of special declaration attributes which require the - /// Foundation module to be imported to work. If the foundation - /// module is still not imported by the time type checking is - /// complete, we diagnose. - llvm::SetVector AttrsRequiringFoundation; - - /// A set of synthesized declarations that need to be type checked. - llvm::SmallVector SynthesizedDecls; - - /// We might perform type checking on the same source file more than once, - /// if its the main file or a REPL instance, so keep track of the last - /// checked synthesized declaration to avoid duplicating work. - unsigned LastCheckedSynthesizedDecl = 0; - - /// A mapping from Objective-C selectors to the methods that have - /// those selectors. - llvm::DenseMap> - ObjCMethods; - - /// List of Objective-C methods, which is used for checking unintended - /// Objective-C overrides. - std::vector ObjCMethodList; - - /// An unsatisfied, optional @objc requirement in a protocol conformance. - using ObjCUnsatisfiedOptReq = std::pair; - - /// List of optional @objc protocol requirements that have gone - /// unsatisfied, which might conflict with other Objective-C methods. - std::vector ObjCUnsatisfiedOptReqs; - - using ObjCMethodConflict = std::tuple; - - /// List of Objective-C member conflicts we have found during type checking. - std::vector ObjCMethodConflicts; - - template - using OperatorMap = llvm::DenseMap>; - - OperatorMap InfixOperators; - OperatorMap PostfixOperators; - OperatorMap PrefixOperators; - OperatorMap PrecedenceGroups; - - /// Describes what kind of file this is, which can affect some type checking - /// and other behavior. - const SourceFileKind Kind; - - enum ASTStage_t { - /// Parsing is underway. - Parsing, - /// Parsing has completed. - Parsed, - /// Name binding has completed. - NameBound, - /// Type checking has completed. - TypeChecked - }; - - /// Defines what phases of parsing and semantic analysis are complete for a - /// source file. - /// - /// Only files that have been fully processed (i.e. type-checked) will be - /// forwarded on to IRGen. - ASTStage_t ASTStage = Parsing; - - SourceFile(ModuleDecl &M, SourceFileKind K, Optional bufferID, - ImplicitModuleImportKind ModImpKind, bool KeepParsedTokens = false, - bool KeepSyntaxTree = false); - - ~SourceFile(); - - void addImports(ArrayRef IM); - - enum ImportQueryKind { - /// Return the results for testable or private imports. - TestableAndPrivate, - /// Return the results only for testable imports. - TestableOnly, - /// Return the results only for private imports. - PrivateOnly - }; - - bool - hasTestableOrPrivateImport(AccessLevel accessLevel, const ValueDecl *ofDecl, - ImportQueryKind kind = TestableAndPrivate) const; - - bool hasImplementationOnlyImports() const { - return HasImplementationOnlyImports; - } - - bool isImportedImplementationOnly(const ModuleDecl *module) const; - - /// This is a hack for 'main' file parsing and the integrated REPL. - /// - /// FIXME: Refactor main file parsing to not pump the parser incrementally. - /// FIXME: Remove the integrated REPL. - void clearLookupCache(); - - void cacheVisibleDecls(SmallVectorImpl &&globals) const; - const SmallVectorImpl &getCachedVisibleDecls() const; - - virtual void lookupValue(DeclName name, NLKind lookupKind, - SmallVectorImpl &result) const override; - - virtual void lookupVisibleDecls(ModuleDecl::AccessPathTy accessPath, - VisibleDeclConsumer &consumer, - NLKind lookupKind) const override; - - virtual void lookupClassMembers(ModuleDecl::AccessPathTy accessPath, - VisibleDeclConsumer &consumer) const override; - virtual void - lookupClassMember(ModuleDecl::AccessPathTy accessPath, DeclName name, - SmallVectorImpl &results) const override; - - void lookupObjCMethods( - ObjCSelector selector, - SmallVectorImpl &results) const override; - - virtual void getTopLevelDecls(SmallVectorImpl &results) const override; - - virtual void - getPrecedenceGroups(SmallVectorImpl &results) const override; - - virtual TypeDecl *lookupLocalType(llvm::StringRef MangledName) const override; - - virtual void - getLocalTypeDecls(SmallVectorImpl &results) const override; - virtual void - getOpaqueReturnTypeDecls(SmallVectorImpl &results) const override; - - virtual void - getImportedModules(SmallVectorImpl &imports, - ModuleDecl::ImportFilter filter) const override; - - virtual void - collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const override; - - Identifier getDiscriminatorForPrivateValue(const ValueDecl *D) const override; - Identifier getPrivateDiscriminator() const { return PrivateDiscriminator; } - - virtual bool walk(ASTWalker &walker) override; - - /// @{ - - /// Look up the given operator in this file. - /// - /// The file must be name-bound already. If the operator is not found, or if - /// there is an ambiguity, returns null. - /// - /// \param isCascading If true, the lookup of this operator may affect - /// downstream files. - InfixOperatorDecl *lookupInfixOperator(Identifier name, bool isCascading, - SourceLoc diagLoc = {}); - PrefixOperatorDecl *lookupPrefixOperator(Identifier name, bool isCascading, - SourceLoc diagLoc = {}); - PostfixOperatorDecl *lookupPostfixOperator(Identifier name, bool isCascading, - SourceLoc diagLoc = {}); - PrecedenceGroupDecl *lookupPrecedenceGroup(Identifier name, bool isCascading, - SourceLoc diagLoc = {}); - /// @} - - ReferencedNameTracker *getReferencedNameTracker() { - return ReferencedNames ? ReferencedNames.getPointer() : nullptr; - } - const ReferencedNameTracker *getReferencedNameTracker() const { - return ReferencedNames ? ReferencedNames.getPointer() : nullptr; - } - - void createReferencedNameTracker(); - - /// The buffer ID for the file that was imported, or None if there - /// is no associated buffer. - Optional getBufferID() const { - if (BufferID == -1) - return None; - return BufferID; - } - - /// If this buffer corresponds to a file on disk, returns the path. - /// Otherwise, return an empty string. - StringRef getFilename() const; - - /// Retrieve the scope that describes this source file. - ASTScope &getScope(); - - void dump() const; - void dump(raw_ostream &os) const; - - /// Pretty-print the contents of this source file. - /// - /// \param Printer The AST printer used for printing the contents. - /// \param PO Options controlling the printing process. - void print(ASTPrinter &Printer, const PrintOptions &PO); - void print(raw_ostream &OS, const PrintOptions &PO); - - static bool classof(const FileUnit *file) { - return file->getKind() == FileUnitKind::Source; - } - static bool classof(const DeclContext *DC) { - return isa(DC) && classof(cast(DC)); - } - - /// True if this is a "script mode" source file that admits top-level code. - bool isScriptMode() const { - switch (Kind) { - case SourceFileKind::Main: - case SourceFileKind::REPL: - return true; - - case SourceFileKind::Library: - case SourceFileKind::Interface: - case SourceFileKind::SIL: - return false; - } - llvm_unreachable("bad SourceFileKind"); - } - - ClassDecl *getMainClass() const override { - return MainClass; - } - SourceLoc getMainClassDiagLoc() const { - assert(hasMainClass()); - return MainClassDiagLoc; - } - - /// Register a "main" class for the module, complaining if there is more than - /// one. - /// - /// Should only be called during type-checking. - bool registerMainClass(ClassDecl *mainClass, SourceLoc diagLoc); - - /// True if this source file has an application entry point. - /// - /// This is true if the source file either is in script mode or contains - /// a designated main class. - bool hasEntryPoint() const override { - return isScriptMode() || hasMainClass(); - } - - /// Get the root refinement context for the file. The root context may be - /// null if the context hierarchy has not been built yet. Use - /// TypeChecker::getOrBuildTypeRefinementContext() to get a built - /// root of the hierarchy. - TypeRefinementContext *getTypeRefinementContext(); - - /// Set the root refinement context for the file. - void setTypeRefinementContext(TypeRefinementContext *TRC); - - void enableInterfaceHash() { - assert(!hasInterfaceHash()); - InterfaceHash.emplace(); - } - - bool hasInterfaceHash() const { - return InterfaceHash.hasValue(); - } - - void recordInterfaceToken(StringRef token) { - assert(!token.empty()); - InterfaceHash->update(token); - // Add null byte to separate tokens. - uint8_t a[1] = {0}; - InterfaceHash->update(a); - } - - void getInterfaceHash(llvm::SmallString<32> &str) { - llvm::MD5::MD5Result result; - InterfaceHash->final(result); - llvm::MD5::stringifyResult(result, str); - } - - void dumpInterfaceHash(llvm::raw_ostream &out) { - llvm::SmallString<32> str; - getInterfaceHash(str); - out << str << '\n'; - } - - std::vector &getTokenVector(); - - ArrayRef getAllTokens() const; - - bool shouldCollectToken() const; - - bool shouldBuildSyntaxTree() const; - - bool canBeParsedInFull() const; - - bool isSuitableForASTScopes() const { return canBeParsedInFull(); } - - syntax::SourceFileSyntax getSyntaxRoot() const; - void setSyntaxRoot(syntax::SourceFileSyntax &&Root); - bool hasSyntaxRoot() const; - - OpaqueTypeDecl *lookupOpaqueResultType(StringRef MangledName, - LazyResolver *resolver) override; - - void addUnvalidatedDeclWithOpaqueResultType(ValueDecl *vd) { - UnvalidatedDeclsWithOpaqueReturnTypes.insert(vd); - } - - void markDeclWithOpaqueResultTypeAsValidated(ValueDecl *vd); - -private: - - /// If not None, the underlying vector should contain tokens of this source file. - Optional> AllCorrectedTokens; - - std::unique_ptr SyntaxInfo; -}; - - /// This represents the compiler's implicitly generated declarations in the /// Builtin module. class BuiltinUnit final : public FileUnit { @@ -783,13 +352,6 @@ class LoadedFile : public FileUnit { }; -inline SourceFile & -ModuleDecl::getMainSourceFile(SourceFileKind expectedKind) const { - assert(!Files.empty() && "No files added yet"); - assert(cast(Files.front())->Kind == expectedKind); - return *cast(Files.front()); -} - inline FileUnit &ModuleDecl::getMainFile(FileUnitKind expectedKind) const { assert(expectedKind != FileUnitKind::Source && "must use specific source kind; see getMainSourceFile"); @@ -798,30 +360,6 @@ inline FileUnit &ModuleDecl::getMainFile(FileUnitKind expectedKind) const { return *Files.front(); } -inline FileUnit *ModuleDecl::EntryPointInfoTy::getEntryPointFile() const { - return storage.getPointer(); -} -inline void ModuleDecl::EntryPointInfoTy::setEntryPointFile(FileUnit *file) { - assert(!storage.getPointer()); - storage.setPointer(file); -} - -inline bool ModuleDecl::EntryPointInfoTy::hasEntryPoint() const { - return storage.getPointer(); -} - -inline bool ModuleDecl::EntryPointInfoTy::markDiagnosedMultipleMainClasses() { - bool res = storage.getInt().contains(Flags::DiagnosedMultipleMainClasses); - storage.setInt(storage.getInt() | Flags::DiagnosedMultipleMainClasses); - return !res; -} - -inline bool ModuleDecl::EntryPointInfoTy::markDiagnosedMainClassWithScript() { - bool res = storage.getInt().contains(Flags::DiagnosedMainClassWithScript); - storage.setInt(storage.getInt() | Flags::DiagnosedMainClassWithScript); - return !res; -} - } // end namespace swift #endif diff --git a/include/swift/AST/SourceFile.h b/include/swift/AST/SourceFile.h new file mode 100644 index 0000000000000..b58966009fbb8 --- /dev/null +++ b/include/swift/AST/SourceFile.h @@ -0,0 +1,483 @@ +//===--- SourceFile.h - The contents of a source file -----------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_AST_SOURCEFILE_H +#define SWIFT_AST_SOURCEFILE_H + +#include "swift/AST/FileUnit.h" + +namespace swift { + +/// A file containing Swift source code. +/// +/// This is a .swift or .sil file (or a virtual file, such as the contents of +/// the REPL). Since it contains raw source, it must be parsed and name-bound +/// before being used for anything; a full type-check is also necessary for +/// IR generation. +class SourceFile final : public FileUnit { +public: + class Impl; + struct SourceFileSyntaxInfo; + + /// The implicit module import that the SourceFile should get. + enum class ImplicitModuleImportKind { + None, + Builtin, + Stdlib + }; + + /// Possible attributes for imports in source files. + enum class ImportFlags { + /// The imported module is exposed to anyone who imports the parent module. + Exported = 0x1, + + /// This source file has access to testable declarations in the imported + /// module. + Testable = 0x2, + + /// This source file has access to private declarations in the imported + /// module. + PrivateImport = 0x4, + + /// The imported module is an implementation detail of this file and should + /// not be required to be present if the main module is ever imported + /// elsewhere. + /// + /// Mutually exclusive with Exported. + ImplementationOnly = 0x8 + }; + + /// \see ImportFlags + using ImportOptions = OptionSet; + + struct ImportedModuleDesc { + ModuleDecl::ImportedModule module; + ImportOptions importOptions; + StringRef filename; + + ImportedModuleDesc(ModuleDecl::ImportedModule module, ImportOptions options, + StringRef filename = {}) + : module(module), importOptions(options), filename(filename) { + assert(!(importOptions.contains(ImportFlags::Exported) && + importOptions.contains(ImportFlags::ImplementationOnly))); + } + }; + +private: + std::unique_ptr Cache; + SourceLookupCache &getCache() const; + + /// This is the list of modules that are imported by this module. + /// + /// This is filled in by the Name Binding phase. + ArrayRef Imports; + + /// A unique identifier representing this file; used to mark private decls + /// within the file to keep them from conflicting with other files in the + /// same module. + mutable Identifier PrivateDiscriminator; + + /// The root TypeRefinementContext for this SourceFile. + /// + /// This is set during type checking. + TypeRefinementContext *TRC = nullptr; + + /// If non-null, used to track name lookups that happen within this file. + Optional ReferencedNames; + + /// The class in this file marked \@NS/UIApplicationMain. + ClassDecl *MainClass = nullptr; + + /// The source location of the main class. + SourceLoc MainClassDiagLoc; + + /// A hash of all interface-contributing tokens that have been lexed for + /// this source file so far. + /// We only collect interface hash for primary input files. + llvm::Optional InterfaceHash; + + /// The ID for the memory buffer containing this file's source. + /// + /// May be -1, to indicate no association with a buffer. + int BufferID; + + /// Does this source file have any implementation-only imports? + /// If not, we can fast-path module checks. + bool HasImplementationOnlyImports = false; + + /// The scope map that describes this source file. + std::unique_ptr Scope; + + friend ASTContext; + friend Impl; +public: + /// The list of top-level declarations in the source file. + std::vector Decls; + + /// A cache of syntax nodes that can be reused when creating the syntax tree + /// for this file. + SyntaxParsingCache *SyntaxParsingCache = nullptr; + + /// The list of local type declarations in the source file. + llvm::SetVector LocalTypeDecls; + + /// The set of validated opaque return type decls in the source file. + llvm::SmallVector OpaqueReturnTypes; + llvm::StringMap ValidatedOpaqueReturnTypes; + /// The set of parsed decls with opaque return types that have not yet + /// been validated. + llvm::DenseSet UnvalidatedDeclsWithOpaqueReturnTypes; + + /// A set of special declaration attributes which require the + /// Foundation module to be imported to work. If the foundation + /// module is still not imported by the time type checking is + /// complete, we diagnose. + llvm::SetVector AttrsRequiringFoundation; + + /// A set of synthesized declarations that need to be type checked. + llvm::SmallVector SynthesizedDecls; + + /// We might perform type checking on the same source file more than once, + /// if its the main file or a REPL instance, so keep track of the last + /// checked synthesized declaration to avoid duplicating work. + unsigned LastCheckedSynthesizedDecl = 0; + + /// A mapping from Objective-C selectors to the methods that have + /// those selectors. + llvm::DenseMap> + ObjCMethods; + + /// List of Objective-C methods, which is used for checking unintended + /// Objective-C overrides. + std::vector ObjCMethodList; + + /// An unsatisfied, optional @objc requirement in a protocol conformance. + using ObjCUnsatisfiedOptReq = std::pair; + + /// List of optional @objc protocol requirements that have gone + /// unsatisfied, which might conflict with other Objective-C methods. + std::vector ObjCUnsatisfiedOptReqs; + + using ObjCMethodConflict = std::tuple; + + /// List of Objective-C member conflicts we have found during type checking. + std::vector ObjCMethodConflicts; + + template + using OperatorMap = llvm::DenseMap>; + + OperatorMap InfixOperators; + OperatorMap PostfixOperators; + OperatorMap PrefixOperators; + OperatorMap PrecedenceGroups; + + /// Describes what kind of file this is, which can affect some type checking + /// and other behavior. + const SourceFileKind Kind; + + enum ASTStage_t { + /// Parsing is underway. + Parsing, + /// Parsing has completed. + Parsed, + /// Name binding has completed. + NameBound, + /// Type checking has completed. + TypeChecked + }; + + /// Defines what phases of parsing and semantic analysis are complete for a + /// source file. + /// + /// Only files that have been fully processed (i.e. type-checked) will be + /// forwarded on to IRGen. + ASTStage_t ASTStage = Parsing; + + SourceFile(ModuleDecl &M, SourceFileKind K, Optional bufferID, + ImplicitModuleImportKind ModImpKind, bool KeepParsedTokens = false, + bool KeepSyntaxTree = false); + + ~SourceFile(); + + void addImports(ArrayRef IM); + + enum ImportQueryKind { + /// Return the results for testable or private imports. + TestableAndPrivate, + /// Return the results only for testable imports. + TestableOnly, + /// Return the results only for private imports. + PrivateOnly + }; + + bool + hasTestableOrPrivateImport(AccessLevel accessLevel, const ValueDecl *ofDecl, + ImportQueryKind kind = TestableAndPrivate) const; + + bool hasImplementationOnlyImports() const { + return HasImplementationOnlyImports; + } + + bool isImportedImplementationOnly(const ModuleDecl *module) const; + + /// This is a hack for 'main' file parsing and the integrated REPL. + /// + /// FIXME: Refactor main file parsing to not pump the parser incrementally. + /// FIXME: Remove the integrated REPL. + void clearLookupCache(); + + void cacheVisibleDecls(SmallVectorImpl &&globals) const; + const SmallVectorImpl &getCachedVisibleDecls() const; + + virtual void lookupValue(DeclName name, NLKind lookupKind, + SmallVectorImpl &result) const override; + + virtual void lookupVisibleDecls(ModuleDecl::AccessPathTy accessPath, + VisibleDeclConsumer &consumer, + NLKind lookupKind) const override; + + virtual void lookupClassMembers(ModuleDecl::AccessPathTy accessPath, + VisibleDeclConsumer &consumer) const override; + virtual void + lookupClassMember(ModuleDecl::AccessPathTy accessPath, DeclName name, + SmallVectorImpl &results) const override; + + void lookupObjCMethods( + ObjCSelector selector, + SmallVectorImpl &results) const override; + + virtual void getTopLevelDecls(SmallVectorImpl &results) const override; + + virtual void + getPrecedenceGroups(SmallVectorImpl &results) const override; + + virtual TypeDecl *lookupLocalType(llvm::StringRef MangledName) const override; + + virtual void + getLocalTypeDecls(SmallVectorImpl &results) const override; + virtual void + getOpaqueReturnTypeDecls(SmallVectorImpl &results) const override; + + virtual void + getImportedModules(SmallVectorImpl &imports, + ModuleDecl::ImportFilter filter) const override; + + virtual void + collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const override; + + Identifier getDiscriminatorForPrivateValue(const ValueDecl *D) const override; + Identifier getPrivateDiscriminator() const { return PrivateDiscriminator; } + + virtual bool walk(ASTWalker &walker) override; + + /// @{ + + /// Look up the given operator in this file. + /// + /// The file must be name-bound already. If the operator is not found, or if + /// there is an ambiguity, returns null. + /// + /// \param isCascading If true, the lookup of this operator may affect + /// downstream files. + InfixOperatorDecl *lookupInfixOperator(Identifier name, bool isCascading, + SourceLoc diagLoc = {}); + PrefixOperatorDecl *lookupPrefixOperator(Identifier name, bool isCascading, + SourceLoc diagLoc = {}); + PostfixOperatorDecl *lookupPostfixOperator(Identifier name, bool isCascading, + SourceLoc diagLoc = {}); + PrecedenceGroupDecl *lookupPrecedenceGroup(Identifier name, bool isCascading, + SourceLoc diagLoc = {}); + /// @} + + ReferencedNameTracker *getReferencedNameTracker() { + return ReferencedNames ? ReferencedNames.getPointer() : nullptr; + } + const ReferencedNameTracker *getReferencedNameTracker() const { + return ReferencedNames ? ReferencedNames.getPointer() : nullptr; + } + + void createReferencedNameTracker(); + + /// The buffer ID for the file that was imported, or None if there + /// is no associated buffer. + Optional getBufferID() const { + if (BufferID == -1) + return None; + return BufferID; + } + + /// If this buffer corresponds to a file on disk, returns the path. + /// Otherwise, return an empty string. + StringRef getFilename() const; + + /// Retrieve the scope that describes this source file. + ASTScope &getScope(); + + void dump() const; + void dump(raw_ostream &os) const; + + /// Pretty-print the contents of this source file. + /// + /// \param Printer The AST printer used for printing the contents. + /// \param PO Options controlling the printing process. + void print(ASTPrinter &Printer, const PrintOptions &PO); + void print(raw_ostream &OS, const PrintOptions &PO); + + static bool classof(const FileUnit *file) { + return file->getKind() == FileUnitKind::Source; + } + static bool classof(const DeclContext *DC) { + return isa(DC) && classof(cast(DC)); + } + + /// True if this is a "script mode" source file that admits top-level code. + bool isScriptMode() const { + switch (Kind) { + case SourceFileKind::Main: + case SourceFileKind::REPL: + return true; + + case SourceFileKind::Library: + case SourceFileKind::Interface: + case SourceFileKind::SIL: + return false; + } + llvm_unreachable("bad SourceFileKind"); + } + + ClassDecl *getMainClass() const override { + return MainClass; + } + SourceLoc getMainClassDiagLoc() const { + assert(hasMainClass()); + return MainClassDiagLoc; + } + + /// Register a "main" class for the module, complaining if there is more than + /// one. + /// + /// Should only be called during type-checking. + bool registerMainClass(ClassDecl *mainClass, SourceLoc diagLoc); + + /// True if this source file has an application entry point. + /// + /// This is true if the source file either is in script mode or contains + /// a designated main class. + bool hasEntryPoint() const override { + return isScriptMode() || hasMainClass(); + } + + /// Get the root refinement context for the file. The root context may be + /// null if the context hierarchy has not been built yet. Use + /// TypeChecker::getOrBuildTypeRefinementContext() to get a built + /// root of the hierarchy. + TypeRefinementContext *getTypeRefinementContext(); + + /// Set the root refinement context for the file. + void setTypeRefinementContext(TypeRefinementContext *TRC); + + void enableInterfaceHash() { + assert(!hasInterfaceHash()); + InterfaceHash.emplace(); + } + + bool hasInterfaceHash() const { + return InterfaceHash.hasValue(); + } + + void recordInterfaceToken(StringRef token) { + assert(!token.empty()); + InterfaceHash->update(token); + // Add null byte to separate tokens. + uint8_t a[1] = {0}; + InterfaceHash->update(a); + } + + void getInterfaceHash(llvm::SmallString<32> &str) { + llvm::MD5::MD5Result result; + InterfaceHash->final(result); + llvm::MD5::stringifyResult(result, str); + } + + void dumpInterfaceHash(llvm::raw_ostream &out) { + llvm::SmallString<32> str; + getInterfaceHash(str); + out << str << '\n'; + } + + std::vector &getTokenVector(); + + ArrayRef getAllTokens() const; + + bool shouldCollectToken() const; + + bool shouldBuildSyntaxTree() const; + + bool canBeParsedInFull() const; + + bool isSuitableForASTScopes() const { return canBeParsedInFull(); } + + syntax::SourceFileSyntax getSyntaxRoot() const; + void setSyntaxRoot(syntax::SourceFileSyntax &&Root); + bool hasSyntaxRoot() const; + + OpaqueTypeDecl *lookupOpaqueResultType(StringRef MangledName, + LazyResolver *resolver) override; + + void addUnvalidatedDeclWithOpaqueResultType(ValueDecl *vd) { + UnvalidatedDeclsWithOpaqueReturnTypes.insert(vd); + } + + void markDeclWithOpaqueResultTypeAsValidated(ValueDecl *vd); + +private: + + /// If not None, the underlying vector should contain tokens of this source file. + Optional> AllCorrectedTokens; + + std::unique_ptr SyntaxInfo; +}; + +inline SourceFile & +ModuleDecl::getMainSourceFile(SourceFileKind expectedKind) const { + assert(!Files.empty() && "No files added yet"); + assert(cast(Files.front())->Kind == expectedKind); + return *cast(Files.front()); +} + +inline FileUnit *ModuleDecl::EntryPointInfoTy::getEntryPointFile() const { + return storage.getPointer(); +} +inline void ModuleDecl::EntryPointInfoTy::setEntryPointFile(FileUnit *file) { + assert(!storage.getPointer()); + storage.setPointer(file); +} + +inline bool ModuleDecl::EntryPointInfoTy::hasEntryPoint() const { + return storage.getPointer(); +} + +inline bool ModuleDecl::EntryPointInfoTy::markDiagnosedMultipleMainClasses() { + bool res = storage.getInt().contains(Flags::DiagnosedMultipleMainClasses); + storage.setInt(storage.getInt() | Flags::DiagnosedMultipleMainClasses); + return !res; +} + +inline bool ModuleDecl::EntryPointInfoTy::markDiagnosedMainClassWithScript() { + bool res = storage.getInt().contains(Flags::DiagnosedMainClassWithScript); + storage.setInt(storage.getInt() | Flags::DiagnosedMainClassWithScript); + return !res; +} + +} // end namespace swift + +#endif diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h index c1cff3eaf70af..be9ab9390f66d 100644 --- a/include/swift/Frontend/Frontend.h +++ b/include/swift/Frontend/Frontend.h @@ -20,12 +20,12 @@ #include "swift/AST/DiagnosticConsumer.h" #include "swift/AST/DiagnosticEngine.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/IRGenOptions.h" #include "swift/AST/LinkLibrary.h" #include "swift/AST/Module.h" #include "swift/AST/SILOptions.h" #include "swift/AST/SearchPathOptions.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/DiagnosticOptions.h" #include "swift/Basic/LangOptions.h" #include "swift/Basic/SourceManager.h" diff --git a/include/swift/IDE/IDERequests.h b/include/swift/IDE/IDERequests.h index 3d716384d238b..2247fe65afade 100644 --- a/include/swift/IDE/IDERequests.h +++ b/include/swift/IDE/IDERequests.h @@ -18,8 +18,8 @@ #include "swift/AST/ASTTypeIDs.h" #include "swift/AST/Evaluator.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/SimpleRequest.h" +#include "swift/AST/SourceFile.h" #include "swift/IDE/Utils.h" #include "swift/IDE/IDETypeIDs.h" diff --git a/include/swift/Migrator/ASTMigratorPass.h b/include/swift/Migrator/ASTMigratorPass.h index 7b8f96473f024..847791d2e98c2 100644 --- a/include/swift/Migrator/ASTMigratorPass.h +++ b/include/swift/Migrator/ASTMigratorPass.h @@ -19,6 +19,7 @@ #define SWIFT_MIGRATOR_ASTMIGRATORPASS_H #include "swift/AST/ASTContext.h" +#include "swift/AST/SourceFile.h" #include "swift/Migrator/EditorAdapter.h" namespace swift { diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index a91a322a48e86..13799b5c9dc81 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -37,6 +37,7 @@ #include "swift/AST/PropertyWrappers.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/RawComment.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/SubstitutionMap.h" #include "swift/AST/SILLayout.h" #include "swift/AST/TypeCheckRequests.h" diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index e45a43ff5522a..c7a67f5c32500 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -17,12 +17,12 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/ASTPrinter.h" #include "swift/AST/ASTVisitor.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/Initializer.h" #include "swift/AST/ParameterList.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeVisitor.h" #include "swift/Basic/Defer.h" #include "swift/Basic/QuotedString.h" diff --git a/lib/AST/ASTScope.cpp b/lib/AST/ASTScope.cpp index 46405b0c614bb..e3a1e5aa5a2dc 100644 --- a/lib/AST/ASTScope.cpp +++ b/lib/AST/ASTScope.cpp @@ -19,13 +19,13 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Pattern.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/AST/TypeRepr.h" #include "swift/Basic/NullablePtr.h" diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index 830a9c596b889..82ab8a010403e 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -20,12 +20,12 @@ #include "swift/AST/Attr.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Pattern.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/AST/TypeRepr.h" #include "swift/Basic/STLExtras.h" diff --git a/lib/AST/ASTScopeLookup.cpp b/lib/AST/ASTScopeLookup.cpp index f7f4a60ccd40d..074279719f1ea 100644 --- a/lib/AST/ASTScopeLookup.cpp +++ b/lib/AST/ASTScopeLookup.cpp @@ -19,13 +19,13 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Pattern.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/AST/TypeRepr.h" #include "swift/Basic/STLExtras.h" diff --git a/lib/AST/ASTScopePrinting.cpp b/lib/AST/ASTScopePrinting.cpp index 94690b41ba449..670b7de5fd1db 100644 --- a/lib/AST/ASTScopePrinting.cpp +++ b/lib/AST/ASTScopePrinting.cpp @@ -19,12 +19,12 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Pattern.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/AST/TypeRepr.h" #include "swift/Basic/STLExtras.h" diff --git a/lib/AST/ASTScopeSourceRange.cpp b/lib/AST/ASTScopeSourceRange.cpp index 9008c20176a10..437dc94b4d1be 100644 --- a/lib/AST/ASTScopeSourceRange.cpp +++ b/lib/AST/ASTScopeSourceRange.cpp @@ -19,12 +19,12 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Pattern.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/AST/TypeRepr.h" #include "swift/Basic/STLExtras.h" diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp index 5c9f7c2ceccd3..67cdb1befe200 100644 --- a/lib/AST/ASTVerifier.cpp +++ b/lib/AST/ASTVerifier.cpp @@ -20,7 +20,6 @@ #include "swift/AST/Decl.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/Expr.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/GenericSignature.h" @@ -30,6 +29,7 @@ #include "swift/AST/Pattern.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/Basic/SourceManager.h" #include "swift/Subsystems.h" diff --git a/lib/AST/AccessRequests.cpp b/lib/AST/AccessRequests.cpp index 9068a787f8abb..f3fc0de11f186 100644 --- a/lib/AST/AccessRequests.cpp +++ b/lib/AST/AccessRequests.cpp @@ -15,9 +15,9 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "swift/AST/DiagnosticsCommon.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookupRequests.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Types.h" #include "llvm/Support/MathExtras.h" diff --git a/lib/AST/ConformanceLookupTable.cpp b/lib/AST/ConformanceLookupTable.cpp index bb98d604d569f..bbe68bc18c6e4 100644 --- a/lib/AST/ConformanceLookupTable.cpp +++ b/lib/AST/ConformanceLookupTable.cpp @@ -18,10 +18,10 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "swift/AST/ExistentialLayout.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/ProtocolConformanceRef.h" #include "llvm/Support/SaveAndRestore.h" diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 4d7c01be751f3..e878ce36d396a 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -23,7 +23,6 @@ #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/Expr.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/GenericSignature.h" @@ -39,6 +38,7 @@ #include "swift/AST/PropertyWrappers.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/ResilienceExpansion.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/AST/TypeLoc.h" diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index 321251aba600d..33f0547426792 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -21,6 +21,7 @@ #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" #include "swift/AST/ParseRequests.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Types.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/Basic/SourceManager.h" diff --git a/lib/AST/DiagnosticEngine.cpp b/lib/AST/DiagnosticEngine.cpp index 9b402b40a2b35..22bb41e89c3bc 100644 --- a/lib/AST/DiagnosticEngine.cpp +++ b/lib/AST/DiagnosticEngine.cpp @@ -20,10 +20,10 @@ #include "swift/AST/ASTPrinter.h" #include "swift/AST/Decl.h" #include "swift/AST/DiagnosticSuppression.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/Pattern.h" #include "swift/AST/PrintOptions.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeRepr.h" #include "swift/Basic/SourceManager.h" #include "swift/Config.h" diff --git a/lib/AST/ExperimentalDependenciesSourceFileDepGraphConstructor.cpp b/lib/AST/ExperimentalDependenciesSourceFileDepGraphConstructor.cpp index 8986edfdad3b5..4b9be295c3263 100644 --- a/lib/AST/ExperimentalDependenciesSourceFileDepGraphConstructor.cpp +++ b/lib/AST/ExperimentalDependenciesSourceFileDepGraphConstructor.cpp @@ -21,10 +21,10 @@ #include "swift/AST/ExistentialLayout.h" #include "swift/AST/ExperimentalDependencies.h" #include "swift/AST/FileSystem.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/ModuleLoader.h" #include "swift/AST/NameLookup.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Types.h" #include "swift/Basic/FileSystem.h" #include "swift/Basic/LLVM.h" diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 1c28f6ef5f2ea..814506ba8b72b 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -34,6 +34,7 @@ #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/PrintOptions.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/Basic/Compiler.h" #include "swift/Basic/SourceManager.h" diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index e4b9660a6056a..ce3d0f99ef599 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -20,7 +20,6 @@ #include "swift/AST/ClangModuleLoader.h" #include "swift/AST/DebuggerClient.h" #include "swift/AST/ExistentialLayout.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/ImportCache.h" #include "swift/AST/Initializer.h" @@ -29,6 +28,7 @@ #include "swift/AST/NameLookupRequests.h" #include "swift/AST/ParameterList.h" #include "swift/AST/ReferencedNameTracker.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/SourceManager.h" #include "swift/Basic/Statistic.h" #include "swift/Basic/STLExtras.h" diff --git a/lib/AST/TypeRefinementContext.cpp b/lib/AST/TypeRefinementContext.cpp index 012a66734ebc6..604323bda8db7 100644 --- a/lib/AST/TypeRefinementContext.cpp +++ b/lib/AST/TypeRefinementContext.cpp @@ -16,10 +16,10 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/Stmt.h" #include "swift/AST/Expr.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeRefinementContext.h" #include "swift/Basic/SourceManager.h" diff --git a/lib/AST/UnqualifiedLookup.cpp b/lib/AST/UnqualifiedLookup.cpp index 8649e9ac991cb..b219fb9e27d1f 100644 --- a/lib/AST/UnqualifiedLookup.cpp +++ b/lib/AST/UnqualifiedLookup.cpp @@ -20,7 +20,6 @@ #include "swift/AST/ClangModuleLoader.h" #include "swift/AST/DebuggerClient.h" #include "swift/AST/ExistentialLayout.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/ImportCache.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" @@ -29,6 +28,7 @@ #include "swift/AST/NameLookupRequests.h" #include "swift/AST/ParameterList.h" #include "swift/AST/ReferencedNameTracker.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/STLExtras.h" #include "swift/Basic/SourceManager.h" #include "swift/Basic/Statistic.h" diff --git a/lib/FrontendTool/ReferenceDependencies.cpp b/lib/FrontendTool/ReferenceDependencies.cpp index 22d114526ecd7..ef198c095afd1 100644 --- a/lib/FrontendTool/ReferenceDependencies.cpp +++ b/lib/FrontendTool/ReferenceDependencies.cpp @@ -18,11 +18,11 @@ #include "swift/AST/DiagnosticsFrontend.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/FileSystem.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/ModuleLoader.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ReferencedNameTracker.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Types.h" #include "swift/Basic/FileSystem.h" #include "swift/Basic/LLVM.h" diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index a716698f704ad..264ad206ce04a 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -23,6 +23,7 @@ #include "swift/AST/NameLookup.h" #include "swift/AST/ParameterList.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/SubstitutionMap.h" #include "swift/AST/USRGeneration.h" #include "swift/Basic/Defer.h" diff --git a/lib/IDE/IDETypeChecking.cpp b/lib/IDE/IDETypeChecking.cpp index 2b986a742dfd1..0a609a2fb480a 100644 --- a/lib/IDE/IDETypeChecking.cpp +++ b/lib/IDE/IDETypeChecking.cpp @@ -10,20 +10,20 @@ // //===----------------------------------------------------------------------===// +#include "swift/AST/ASTDemangler.h" #include "swift/AST/ASTPrinter.h" #include "swift/AST/ASTContext.h" -#include "swift/AST/Identifier.h" -#include "swift/AST/Decl.h" -#include "swift/AST/GenericSignature.h" -#include "swift/AST/Types.h" #include "swift/AST/Attr.h" +#include "swift/AST/Decl.h" #include "swift/AST/Expr.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" +#include "swift/AST/GenericSignature.h" +#include "swift/AST/Identifier.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" -#include "swift/AST/ASTDemangler.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/SourceFile.h" +#include "swift/AST/Types.h" #include "swift/Sema/IDETypeChecking.h" #include "swift/Sema/IDETypeCheckingRequests.h" #include "swift/IDE/SourceEntityWalker.h" diff --git a/lib/IDE/ModuleInterfacePrinting.cpp b/lib/IDE/ModuleInterfacePrinting.cpp index 0b3de70e6e350..e87deadb53b05 100644 --- a/lib/IDE/ModuleInterfacePrinting.cpp +++ b/lib/IDE/ModuleInterfacePrinting.cpp @@ -20,6 +20,7 @@ #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" #include "swift/AST/PrintOptions.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/PrimitiveParsing.h" #include "swift/ClangImporter/ClangImporter.h" #include "swift/ClangImporter/ClangModule.h" diff --git a/lib/IDE/REPLCodeCompletion.cpp b/lib/IDE/REPLCodeCompletion.cpp index eb3e9f43672d9..0b7db14712a67 100644 --- a/lib/IDE/REPLCodeCompletion.cpp +++ b/lib/IDE/REPLCodeCompletion.cpp @@ -17,8 +17,8 @@ #include "swift/IDE/REPLCodeCompletion.h" #include "swift/AST/ASTContext.h" #include "swift/AST/DiagnosticSuppression.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/LLVM.h" #include "swift/Basic/SourceManager.h" #include "swift/Parse/Parser.h" diff --git a/lib/IDE/SourceEntityWalker.cpp b/lib/IDE/SourceEntityWalker.cpp index 5a4570a9af022..364b3be704d20 100644 --- a/lib/IDE/SourceEntityWalker.cpp +++ b/lib/IDE/SourceEntityWalker.cpp @@ -16,10 +16,10 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/Pattern.h" #include "swift/AST/ParameterList.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/AST/TypeRepr.h" #include "swift/AST/Types.h" diff --git a/lib/IDE/SyntaxModel.cpp b/lib/IDE/SyntaxModel.cpp index a629842c0c136..60746c1f8b375 100644 --- a/lib/IDE/SyntaxModel.cpp +++ b/lib/IDE/SyntaxModel.cpp @@ -15,10 +15,10 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Pattern.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Module.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/AST/TypeRepr.h" #include "swift/Basic/SourceManager.h" diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index 93fc4172b395b..129b335dd3f1c 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -21,9 +21,9 @@ #include "IRGen.h" #include "SwiftTargetInfo.h" #include "swift/AST/Decl.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/ReferenceCounting.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/ClusteredBitVector.h" #include "swift/Basic/LLVM.h" #include "swift/Basic/OptimizationMode.h" diff --git a/lib/Index/Index.cpp b/lib/Index/Index.cpp index 2fe34cbf1874f..ab9cf98b942c2 100644 --- a/lib/Index/Index.cpp +++ b/lib/Index/Index.cpp @@ -16,10 +16,10 @@ #include "swift/AST/Comment.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Types.h" #include "swift/AST/USRGeneration.h" #include "swift/Basic/SourceManager.h" diff --git a/lib/Index/IndexRecord.cpp b/lib/Index/IndexRecord.cpp index ef0f97ccff04a..162e47a6a4955 100644 --- a/lib/Index/IndexRecord.cpp +++ b/lib/Index/IndexRecord.cpp @@ -13,14 +13,15 @@ #include "swift/Index/IndexRecord.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" +#include "swift/AST/DiagnosticsFrontend.h" #include "swift/AST/Expr.h" #include "swift/AST/Module.h" +#include "swift/AST/ModuleLoader.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Pattern.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/AST/Types.h" -#include "swift/AST/DiagnosticsFrontend.h" -#include "swift/AST/ModuleLoader.h" #include "swift/ClangImporter/ClangModule.h" #include "swift/Index/Index.h" #include "clang/Basic/FileManager.h" diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 726e817d0c3cd..fc485f86845a3 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -26,10 +26,10 @@ #include "swift/AST/DebuggerClient.h" #include "swift/AST/DiagnosticsParse.h" #include "swift/AST/Initializer.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" #include "swift/AST/ParseRequests.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/Defer.h" #include "swift/Basic/Statistic.h" #include "swift/Basic/StringExtras.h" diff --git a/lib/Parse/ParsePattern.cpp b/lib/Parse/ParsePattern.cpp index e7461149276cd..2481cdae14c43 100644 --- a/lib/Parse/ParsePattern.cpp +++ b/lib/Parse/ParsePattern.cpp @@ -18,8 +18,8 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/Initializer.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/StringExtras.h" #include "swift/Parse/CodeCompletionCallbacks.h" #include "swift/Parse/ParsedSyntaxRecorder.h" diff --git a/lib/Parse/ParseRequests.cpp b/lib/Parse/ParseRequests.cpp index 0ee4fffcd831d..620c2e7999623 100644 --- a/lib/Parse/ParseRequests.cpp +++ b/lib/Parse/ParseRequests.cpp @@ -17,8 +17,8 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "swift/AST/DeclContext.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" +#include "swift/AST/SourceFile.h" #include "swift/Parse/Parser.h" #include "swift/Subsystems.h" diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 02ea50cde22cd..368b014e43b86 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -18,9 +18,9 @@ #include "swift/Subsystems.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/DiagnosticsParse.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/PrettyStackTrace.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/Defer.h" #include "swift/Basic/SourceManager.h" #include "swift/Basic/Timer.h" diff --git a/lib/Parse/SyntaxParsingContext.cpp b/lib/Parse/SyntaxParsingContext.cpp index 5f1473ac880c7..36bb55a4ad812 100644 --- a/lib/Parse/SyntaxParsingContext.cpp +++ b/lib/Parse/SyntaxParsingContext.cpp @@ -15,8 +15,8 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/DiagnosticsParse.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/Defer.h" #include "swift/Parse/ParsedSyntax.h" #include "swift/Parse/ParsedSyntaxRecorder.h" diff --git a/lib/ParseSIL/ParseSIL.cpp b/lib/ParseSIL/ParseSIL.cpp index acec522fffbdb..cededafc650aa 100644 --- a/lib/ParseSIL/ParseSIL.cpp +++ b/lib/ParseSIL/ParseSIL.cpp @@ -13,10 +13,10 @@ #include "SILParserFunctionBuilder.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/ExistentialLayout.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/Basic/Defer.h" #include "swift/Basic/Timer.h" diff --git a/lib/SIL/SILProfiler.cpp b/lib/SIL/SILProfiler.cpp index 8af1fe45d8c3a..b6ce5e18b3b1a 100644 --- a/lib/SIL/SILProfiler.cpp +++ b/lib/SIL/SILProfiler.cpp @@ -14,8 +14,8 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/Parse/Lexer.h" #include "swift/SIL/FormalLinkage.h" diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index 8b14bf29901e2..20be4e6fdf8c7 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -25,6 +25,7 @@ #include "swift/AST/PropertyWrappers.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/ResilienceExpansion.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/Basic/Statistic.h" #include "swift/Basic/Timer.h" diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp index f02bfac7b3efd..4aa67bf9a18a2 100644 --- a/lib/SILGen/SILGenType.cpp +++ b/lib/SILGen/SILGenType.cpp @@ -22,10 +22,10 @@ #include "SILGenFunctionBuilder.h" #include "Scope.h" #include "swift/AST/ASTMangler.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/PrettyStackTrace.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/SubstitutionMap.h" #include "swift/AST/TypeMemberVisitor.h" #include "swift/SIL/FormalLinkage.h" diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 4399e3ea9c4a5..21612431b3604 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -22,13 +22,13 @@ #include "swift/AST/Decl.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/Expr.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/Initializer.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Pattern.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/ProtocolConformanceRef.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/AST/Types.h" #include "swift/Basic/SourceLoc.h" diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index 416fc79cee176..962d8a4be482c 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -29,6 +29,7 @@ #include "swift/AST/ParameterList.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/Basic/Defer.h" #include "swift/ClangImporter/ClangModule.h" diff --git a/lib/Sema/DebuggerTestingTransform.cpp b/lib/Sema/DebuggerTestingTransform.cpp index 415cfa97e8a20..cb85e9998a4e3 100644 --- a/lib/Sema/DebuggerTestingTransform.cpp +++ b/lib/Sema/DebuggerTestingTransform.cpp @@ -21,9 +21,9 @@ #include "swift/AST/Decl.h" #include "swift/AST/DeclContext.h" #include "swift/AST/Expr.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/Subsystems.h" diff --git a/lib/Sema/InstrumenterSupport.cpp b/lib/Sema/InstrumenterSupport.cpp index 52663685e0429..cf09f836343ba 100644 --- a/lib/Sema/InstrumenterSupport.cpp +++ b/lib/Sema/InstrumenterSupport.cpp @@ -17,7 +17,7 @@ #include "InstrumenterSupport.h" #include "swift/AST/DiagnosticSuppression.h" -#include "swift/AST/FileUnit.h" +#include "swift/AST/SourceFile.h" #include "swift/Demangling/Punycode.h" #include "llvm/Support/Path.h" diff --git a/lib/Sema/LookupVisibleDecls.cpp b/lib/Sema/LookupVisibleDecls.cpp index 2958ec8aadeb0..4327e7cd161aa 100644 --- a/lib/Sema/LookupVisibleDecls.cpp +++ b/lib/Sema/LookupVisibleDecls.cpp @@ -16,7 +16,6 @@ //===----------------------------------------------------------------------===// #include "swift/AST/ASTContext.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/GenericSignatureBuilder.h" #include "swift/AST/ImportCache.h" @@ -25,6 +24,7 @@ #include "swift/AST/ModuleNameLookup.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/SourceManager.h" #include "swift/Basic/STLExtras.h" #include "swift/Sema/IDETypeCheckingRequests.h" diff --git a/lib/Sema/NameBinding.cpp b/lib/Sema/NameBinding.cpp index 0d532c8713f06..108ca14998236 100644 --- a/lib/Sema/NameBinding.cpp +++ b/lib/Sema/NameBinding.cpp @@ -19,6 +19,7 @@ #include "swift/AST/ModuleLoader.h" #include "swift/AST/ModuleNameLookup.h" #include "swift/AST/NameLookup.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/SubstitutionMap.h" #include "swift/Basic/Statistic.h" #include "swift/ClangImporter/ClangModule.h" diff --git a/lib/Sema/PCMacro.cpp b/lib/Sema/PCMacro.cpp index f5686ab1c4319..a2f52b7371dcd 100644 --- a/lib/Sema/PCMacro.cpp +++ b/lib/Sema/PCMacro.cpp @@ -22,10 +22,10 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Module.h" #include "swift/AST/Pattern.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" using namespace swift; diff --git a/lib/Sema/PlaygroundTransform.cpp b/lib/Sema/PlaygroundTransform.cpp index 55e53c3c429be..e722d7df42fe2 100644 --- a/lib/Sema/PlaygroundTransform.cpp +++ b/lib/Sema/PlaygroundTransform.cpp @@ -20,9 +20,9 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "swift/AST/DeclContext.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/Pattern.h" +#include "swift/AST/SourceFile.h" #include #include diff --git a/lib/Sema/ResilienceDiagnostics.cpp b/lib/Sema/ResilienceDiagnostics.cpp index 42170257bdb77..b77ac07675e34 100644 --- a/lib/Sema/ResilienceDiagnostics.cpp +++ b/lib/Sema/ResilienceDiagnostics.cpp @@ -19,9 +19,9 @@ #include "swift/AST/Attr.h" #include "swift/AST/Decl.h" #include "swift/AST/DeclContext.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Initializer.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeDeclFinder.h" using namespace swift; diff --git a/lib/Sema/SourceLoader.cpp b/lib/Sema/SourceLoader.cpp index e9d41823c1ee5..3026605d6faf5 100644 --- a/lib/Sema/SourceLoader.cpp +++ b/lib/Sema/SourceLoader.cpp @@ -19,8 +19,8 @@ #include "swift/Subsystems.h" #include "swift/AST/ASTContext.h" #include "swift/AST/DiagnosticsSema.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" +#include "swift/AST/SourceFile.h" #include "swift/Parse/PersistentParserState.h" #include "swift/Basic/SourceManager.h" #include "llvm/ADT/SmallString.h" diff --git a/lib/Sema/TypeAccessScopeChecker.h b/lib/Sema/TypeAccessScopeChecker.h index 5966dee3f2372..2e8b8990204bf 100644 --- a/lib/Sema/TypeAccessScopeChecker.h +++ b/lib/Sema/TypeAccessScopeChecker.h @@ -15,7 +15,7 @@ #include "swift/AST/Decl.h" #include "swift/AST/DeclContext.h" -#include "swift/AST/FileUnit.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Type.h" #include "swift/AST/TypeDeclFinder.h" #include "swift/AST/TypeRepr.h" diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index aa5f90eb7e238..429adae45002e 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -21,7 +21,6 @@ #include "swift/AST/ASTVisitor.h" #include "swift/AST/ClangModuleLoader.h" #include "swift/AST/DiagnosticsParse.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/GenericSignatureBuilder.h" #include "swift/AST/ModuleNameLookup.h" @@ -29,6 +28,7 @@ #include "swift/AST/NameLookupRequests.h" #include "swift/AST/ParameterList.h" #include "swift/AST/PropertyWrappers.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/AST/Types.h" #include "swift/Parse/Lexer.h" diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp index e7ecee8cd3a3d..2b48f3e8b470a 100644 --- a/lib/Sema/TypeCheckAvailability.cpp +++ b/lib/Sema/TypeCheckAvailability.cpp @@ -19,10 +19,10 @@ #include "TypeCheckObjC.h" #include "MiscDiagnostics.h" #include "swift/AST/ASTWalker.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Initializer.h" #include "swift/AST/NameLookup.h" #include "swift/AST/Pattern.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeRefinementContext.h" #include "swift/Basic/Defer.h" #include "swift/Basic/SourceManager.h" diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index aa4fa99b7c56b..2ce556b29e8a3 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -39,6 +39,7 @@ #include "swift/AST/PropertyWrappers.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/ReferencedNameTracker.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeWalker.h" #include "swift/Basic/Statistic.h" #include "swift/Parse/Lexer.h" diff --git a/lib/Sema/TypeCheckDeclObjC.cpp b/lib/Sema/TypeCheckDeclObjC.cpp index 708257c632981..74213e6b6dbdd 100644 --- a/lib/Sema/TypeCheckDeclObjC.cpp +++ b/lib/Sema/TypeCheckDeclObjC.cpp @@ -20,10 +20,10 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "swift/AST/ExistentialLayout.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/ImportCache.h" #include "swift/AST/ParameterList.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/Basic/StringExtras.h" using namespace swift; diff --git a/lib/Sema/TypeCheckExpr.cpp b/lib/Sema/TypeCheckExpr.cpp index d0e0787e9080a..2f6a65a3975b0 100644 --- a/lib/Sema/TypeCheckExpr.cpp +++ b/lib/Sema/TypeCheckExpr.cpp @@ -18,9 +18,9 @@ #include "TypeChecker.h" #include "swift/AST/NameLookup.h" #include "swift/AST/Decl.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Initializer.h" #include "swift/AST/ParameterList.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/Parse/Lexer.h" using namespace swift; diff --git a/lib/Sema/TypeCheckREPL.cpp b/lib/Sema/TypeCheckREPL.cpp index b3f35d55bbaad..5760db078057c 100644 --- a/lib/Sema/TypeCheckREPL.cpp +++ b/lib/Sema/TypeCheckREPL.cpp @@ -19,9 +19,9 @@ #include "swift/AST/ASTVisitor.h" #include "swift/AST/DiagnosticsFrontend.h" #include "swift/AST/Expr.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ParameterList.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/Parse/LocalContext.h" #include "llvm/ADT/SmallString.h" diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index cd16844981489..d271f8fc603d4 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -25,12 +25,12 @@ #include "swift/AST/ASTVisitor.h" #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/DiagnosticSuppression.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Identifier.h" #include "swift/AST/Initializer.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ParameterList.h" #include "swift/AST/PrettyStackTrace.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/Basic/Range.h" #include "swift/Basic/STLExtras.h" diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index 56d89e81861ba..5b1d0f8b8e931 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -24,12 +24,12 @@ #include "swift/AST/DiagnosticsParse.h" #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/Expr.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/Initializer.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Pattern.h" #include "swift/AST/PropertyWrappers.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/AST/Types.h" using namespace swift; diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 0dc0679213643..d3d267a0c51b8 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -27,7 +27,6 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/DiagnosticsParse.h" #include "swift/AST/ExistentialLayout.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/GenericSignatureBuilder.h" @@ -35,6 +34,7 @@ #include "swift/AST/ParameterList.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeLoc.h" #include "swift/AST/TypeResolutionStage.h" #include "swift/Basic/SourceManager.h" diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp index 9834c4ee09261..8382e4196c16a 100644 --- a/lib/Sema/TypeChecker.cpp +++ b/lib/Sema/TypeChecker.cpp @@ -26,7 +26,6 @@ #include "swift/AST/Attr.h" #include "swift/AST/DiagnosticSuppression.h" #include "swift/AST/ExistentialLayout.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Identifier.h" #include "swift/AST/ImportCache.h" #include "swift/AST/Initializer.h" @@ -34,6 +33,7 @@ #include "swift/AST/NameLookup.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/Statistic.h" #include "swift/Basic/STLExtras.h" #include "swift/Basic/Timer.h" diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 8069509646f36..cb7f29e4fafe2 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -29,6 +29,7 @@ #include "swift/AST/PropertyWrappers.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/RawComment.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/AST/TypeVisitor.h" #include "swift/Basic/Dwarf.h" diff --git a/lib/Serialization/SerializeDoc.cpp b/lib/Serialization/SerializeDoc.cpp index cd5cd5e9c99f4..d3a0e58c43d8c 100644 --- a/lib/Serialization/SerializeDoc.cpp +++ b/lib/Serialization/SerializeDoc.cpp @@ -16,9 +16,9 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/DiagnosticsCommon.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/USRGeneration.h" #include "swift/Basic/SourceManager.h" #include "llvm/Support/DJB.h" diff --git a/lib/SyntaxParse/SyntaxTreeCreator.cpp b/lib/SyntaxParse/SyntaxTreeCreator.cpp index d9f7dc253b7a3..dfa07cf136251 100644 --- a/lib/SyntaxParse/SyntaxTreeCreator.cpp +++ b/lib/SyntaxParse/SyntaxTreeCreator.cpp @@ -19,8 +19,8 @@ #include "swift/Parse/Token.h" #include "swift/AST/ASTContext.h" #include "swift/AST/DiagnosticsParse.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/OwnedString.h" #include "RawSyntaxTokenCache.h" diff --git a/unittests/AST/TestContext.h b/unittests/AST/TestContext.h index db2625a0d8dab..428a933b0cd01 100644 --- a/unittests/AST/TestContext.h +++ b/unittests/AST/TestContext.h @@ -12,8 +12,8 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/DiagnosticEngine.h" -#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/LangOptions.h" #include "swift/Basic/SourceManager.h" From 5d1a1ff57dc43271db89964c0441e0efd8d7373c Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Wed, 18 Sep 2019 01:56:10 +0100 Subject: [PATCH 065/199] [Typechecker] Use an equal constraint between a property wrapper's value type and the pattern init --- lib/Sema/TypeCheckConstraints.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 74d1e7c880e82..6efc798b80ab6 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -2633,7 +2633,7 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer, emptyLocator); return propertyType; } - + // Otherwise, compute the wrapped value type directly. return computeWrappedValueType(wrappedVar, initType); } @@ -2654,10 +2654,10 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer, // is the initialization of the property wrapper instance. initType = cs.getType(expr); - // Add a conversion constraint between the pattern type and the + // Add an equal constraint between the pattern type and the // property wrapper's "value" type. - cs.addConstraint(ConstraintKind::Conversion, patternType, - getPatternInitType(&cs), Locator, /*isFavored*/true); + cs.addConstraint(ConstraintKind::Equal, patternType, + getPatternInitType(&cs), Locator, /*isFavored*/ true); } else { // The initializer type is the type of the pattern. initType = patternType; From b3d3ef3867854cc9e82102b1054539553b88833b Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Wed, 18 Sep 2019 01:58:24 +0100 Subject: [PATCH 066/199] [Test] Adds a test case --- test/decl/var/property_wrappers.swift | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/decl/var/property_wrappers.swift b/test/decl/var/property_wrappers.swift index 28822b7db011d..a684e6cc1a78f 100644 --- a/test/decl/var/property_wrappers.swift +++ b/test/decl/var/property_wrappers.swift @@ -1683,3 +1683,17 @@ final class SR_11478_C2 { @SR_11478_W class var bool2: Bool = true // expected-error {{class stored properties not supported in classes; did you mean 'static'?}} @SR_11478_W class final var bool3: Bool = true // expected-error {{class stored properties not supported in classes; did you mean 'static'?}} } + +// SR-11381 + +@propertyWrapper +struct SR_11381_W { + init(wrappedValue: T) {} + var wrappedValue: T { + fatalError() + } +} + +struct SR_11381_S { + @SR_11381_W var foo: Int = nil // expected-error {{'nil' is not compatible with expected argument type 'Int'}} +} From 6b7fbc9a2bdc3b192d5bf5c6ea2daaecf384660b Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 17 Sep 2019 18:29:40 -0700 Subject: [PATCH 067/199] Break some cycles Use the interface type of the underlying type in the GSB in as many cases as possible except for one important one: requirement signature computation. There, use the structural type so we don't wind up recursively validating the requirements of an incomplete protocol. --- lib/AST/GenericSignatureBuilder.cpp | 8 +++++++- test/Generics/protocol_type_aliases.swift | 4 ++-- .../compiler_crashers_2_fixed/0145-sr7097.swift | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp index 1aedddaa59276..65f23e9a1ad94 100644 --- a/lib/AST/GenericSignatureBuilder.cpp +++ b/lib/AST/GenericSignatureBuilder.cpp @@ -3785,7 +3785,13 @@ PotentialArchetype *GenericSignatureBuilder::realizePotentialArchetype( static Type getStructuralType(TypeDecl *typeDecl) { if (auto typealias = dyn_cast(typeDecl)) { - return typealias->getStructuralType(); + // When we're computing requirement signatures, the structural type + // suffices. Otherwise we'll potentially try to validate incomplete + // requirements. + auto *proto = dyn_cast_or_null(typealias->getDeclContext()->getAsDecl()); + if (proto && proto->isComputingRequirementSignature()) + return typealias->getStructuralType(); + return typealias->getUnderlyingType(); } return typeDecl->getDeclaredInterfaceType(); diff --git a/test/Generics/protocol_type_aliases.swift b/test/Generics/protocol_type_aliases.swift index 8804caa6cf74c..d922423bf664a 100644 --- a/test/Generics/protocol_type_aliases.swift +++ b/test/Generics/protocol_type_aliases.swift @@ -42,14 +42,14 @@ func concreteRequirementOnConcreteNestedTypeAlias(_: T) where T: Q2, S = protocol P3 { typealias T = Int } -protocol Q3: P3 { // expected-error{{generic signature requires types 'P3.T' (aka 'Int')}} +protocol Q3: P3 { // expected-error{{generic signature requires types 'Int'}} typealias T = Float } protocol P3_1 { typealias T = Float } -protocol Q3_1: P3, P3_1 {} // expected-error{{generic signature requires types 'P3_1.T' (aka 'Float')}} +protocol Q3_1: P3, P3_1 {} // expected-error{{generic signature requires types 'Float'}} // Subprotocols can force associated types in their parents to be concrete, and diff --git a/validation-test/compiler_crashers_2_fixed/0145-sr7097.swift b/validation-test/compiler_crashers_2_fixed/0145-sr7097.swift index 2e6adfc824840..bc369c7f47a02 100644 --- a/validation-test/compiler_crashers_2_fixed/0145-sr7097.swift +++ b/validation-test/compiler_crashers_2_fixed/0145-sr7097.swift @@ -9,7 +9,7 @@ protocol P2 { } // CHECK-LABEL: .P3@ -// CHECK-NEXT: Requirement signature: +// CHECK-NEXT: Requirement signature: protocol P3 : P2 { } struct S0 where M.Assoc: P1 { } // expected-warning{{redundant conformance constraint 'M.Assoc': 'P1'}} From 54defbc7f747cf9dd7396ec18cc1f93242bd2d5e Mon Sep 17 00:00:00 2001 From: Nathan Hawes Date: Tue, 17 Sep 2019 14:28:32 -0700 Subject: [PATCH 068/199] [code-completion] Remove special handling for completion on the RHS of an assignment This simplifies the code and prevents an assertion failure this code was hitting computing the type relations between the result types and what it determined as the expected type. Resolves rdar://problem/53958454 --- include/swift/IDE/CodeCompletion.h | 1 - include/swift/Parse/CodeCompletionCallbacks.h | 2 - lib/IDE/CodeCompletion.cpp | 18 ------- lib/Parse/ParseExpr.cpp | 22 -------- test/IDE/complete_associated_types.swift | 50 +++++++++++++++++++ .../lib/SwiftLang/CodeCompletionOrganizer.cpp | 1 - 6 files changed, 50 insertions(+), 44 deletions(-) diff --git a/include/swift/IDE/CodeCompletion.h b/include/swift/IDE/CodeCompletion.h index 427013647a6c8..e6b2d63290a49 100644 --- a/include/swift/IDE/CodeCompletion.h +++ b/include/swift/IDE/CodeCompletion.h @@ -498,7 +498,6 @@ enum class CompletionKind { AttributeBegin, AttributeDeclParen, PoundAvailablePlatform, - AssignmentRHS, CallArg, ReturnStmtExpr, YieldStmtExpr, diff --git a/include/swift/Parse/CodeCompletionCallbacks.h b/include/swift/Parse/CodeCompletionCallbacks.h index 6117ea5d9a2a9..cf18c459c642e 100644 --- a/include/swift/Parse/CodeCompletionCallbacks.h +++ b/include/swift/Parse/CodeCompletionCallbacks.h @@ -200,8 +200,6 @@ class CodeCompletionCallbacks { virtual void completeUnresolvedMember(CodeCompletionExpr *E, SourceLoc DotLoc) {}; - virtual void completeAssignmentRHS(AssignExpr *E) {}; - virtual void completeCallArg(CodeCompletionExpr *E, bool isFirst) {}; virtual void completeReturnStmt(CodeCompletionExpr *E) {}; diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index a716698f704ad..35ffe0227728f 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -1213,7 +1213,6 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks { std::vector RequestedModules; CodeCompletionConsumer &Consumer; CodeCompletionExpr *CodeCompleteTokenExpr = nullptr; - AssignExpr *AssignmentExpr; CompletionKind Kind = CompletionKind::None; Expr *ParsedExpr = nullptr; SourceLoc DotLoc; @@ -1367,7 +1366,6 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks { void completeImportDecl(std::vector> &Path) override; void completeUnresolvedMember(CodeCompletionExpr *E, SourceLoc DotLoc) override; - void completeAssignmentRHS(AssignExpr *E) override; void completeCallArg(CodeCompletionExpr *E, bool isFirst) override; void completeReturnStmt(CodeCompletionExpr *E) override; void completeYieldStmt(CodeCompletionExpr *E, @@ -4671,13 +4669,6 @@ void CodeCompletionCallbacksImpl::completeUnresolvedMember(CodeCompletionExpr *E this->DotLoc = DotLoc; } -void CodeCompletionCallbacksImpl::completeAssignmentRHS(AssignExpr *E) { - AssignmentExpr = E; - ParsedExpr = E->getDest(); - CurDeclContext = P.CurDeclContext; - Kind = CompletionKind::AssignmentRHS; -} - void CodeCompletionCallbacksImpl::completeCallArg(CodeCompletionExpr *E, bool isFirst) { CurDeclContext = P.CurDeclContext; @@ -4906,7 +4897,6 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink, addDeclKeywords(Sink); addStmtKeywords(Sink, MaybeFuncBody); LLVM_FALLTHROUGH; - case CompletionKind::AssignmentRHS: case CompletionKind::ReturnStmtExpr: case CompletionKind::YieldStmtExpr: case CompletionKind::PostfixExprBeginning: @@ -5373,14 +5363,6 @@ void CodeCompletionCallbacksImpl::doneParsing() { Lookup.getUnresolvedMemberCompletions(ContextInfo.getPossibleTypes()); break; } - case CompletionKind::AssignmentRHS : { - SourceLoc Loc = P.Context.SourceMgr.getCodeCompletionLoc(); - if (auto destType = ParsedExpr->getType()) - Lookup.setExpectedTypes(destType->getRValueType(), - /*isSingleExpressionBody*/ false); - Lookup.getValueCompletionsInDeclContext(Loc, DefaultFilter); - break; - } case CompletionKind::CallArg : { ExprContextInfo ContextInfo(CurDeclContext, CodeCompleteTokenExpr); diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 211cf97860f73..ef530a814a7d8 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -279,28 +279,6 @@ ParserResult Parser::parseExprSequence(Diag<> Message, auto *assign = new (Context) AssignExpr(equalsLoc); SequencedExprs.push_back(assign); Message = diag::expected_expr_assignment; - if (Tok.is(tok::code_complete)) { - if (CodeCompletion) { - auto RHS = new (Context) ErrorExpr( - SourceRange(Tok.getRange().getStart(), Tok.getRange().getEnd())); - assign->setSrc(RHS); - SequencedExprs.pop_back(); - assign->setDest(SequencedExprs.back()); - SequencedExprs.pop_back(); - SequencedExprs.push_back(assign); - CodeCompletion->completeAssignmentRHS(assign); - } - consumeToken(); - if (!SequencedExprs.empty() && (SequencedExprs.size() & 1) == 0) { - // Make sure we have odd number of sequence exprs. - SequencedExprs.pop_back(); - } - auto Result = SequencedExprs.size() == 1 ? - makeParserResult(SequencedExprs[0]): - makeParserResult(SequenceExpr::create(Context, SequencedExprs)); - Result.setHasCodeCompletion(); - return Result; - } break; } diff --git a/test/IDE/complete_associated_types.swift b/test/IDE/complete_associated_types.swift index 711c615cf7525..6da3919844627 100644 --- a/test/IDE/complete_associated_types.swift +++ b/test/IDE/complete_associated_types.swift @@ -20,6 +20,15 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=BROKEN_CONFORMANCE_1 > %t.types.txt // RUN: %FileCheck %s -check-prefix=BROKEN_CONFORMANCE_1 < %t.types.txt +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=BROKEN_CONFORMANCE_UNASSIGNABLE > %t.types.txt +// RUN: %FileCheck %s -check-prefix=BROKEN_CONFORMANCE_UNASSIGNABLE < %t.types.txt + +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=BROKEN_CONFORMANCE_UNASSIGNABLE_2 > %t.types.txt +// RUN: %FileCheck %s -check-prefix=BROKEN_CONFORMANCE_UNASSIGNABLE < %t.types.txt + +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=BROKEN_CONFORMANCE_ASSIGNABLE > %t.types.txt +// RUN: %FileCheck %s -check-prefix=BROKEN_CONFORMANCE_ASSIGNABLE < %t.types.txt + // FIXME: extensions that introduce conformances? protocol FooBaseProtocolWithAssociatedTypes { @@ -300,3 +309,44 @@ func testBrokenConformances1() { // BROKEN_CONFORMANCE_1-DAG: Decl[InstanceMethod]/Super: deduceFooBaseC({#(self): StructWithBrokenConformance#})[#() -> StructWithBrokenConformance.FooBaseDeducedTypeC#]{{; name=.+$}} // BROKEN_CONFORMANCE_1-DAG: Decl[InstanceMethod]/Super: deduceFooBaseD({#(self): StructWithBrokenConformance#})[#() -> StructWithBrokenConformance.FooBaseDeducedTypeD#]{{; name=.+$}} // BROKEN_CONFORMANCE_1: End completions + + +protocol MyProto { + associatedtype Element +} + +extension MyProto { + var matches: (Int, (Int, Int)) { fatalError() } + func first() -> Element { + fatalError() + } +} + +// Does not conform - Element not specified +struct A: MyProto { + func foo() { + self.first = #^BROKEN_CONFORMANCE_UNASSIGNABLE^# + } + + func foo2() { + var (a, b): (Int, Int) + let exact = (1, (2, 4)) + (a, (b, self.first)) = #^BROKEN_CONFORMANCE_UNASSIGNABLE_2^# + } + + func foo3() { + var (a, b, c): (Int, Int, Int) + let exact = (1, (2, 4)) + (a, (b, c)) = #^BROKEN_CONFORMANCE_ASSIGNABLE^# + } +} +// BROKEN_CONFORMANCE_UNASSIGNABLE: Begin completions +// BROKEN_CONFORMANCE_UNASSIGNABLE-NOT: TypeRelation +// BROKEN_CONFORMANCE_UNASSIGNABLE: Decl[InstanceMethod]/Super: first()[#MyProto.Element#]; name=first() +// BROKEN_CONFORMANCE_UNASSIGNABLE-NOT: TypeRelation +// BROKEN_CONFORMANCE_UNASSIGNABLE: End completions + +// BROKEN_CONFORMANCE_ASSIGNABLE: Begin completions +// BROKEN_CONFORMANCE_ASSIGNABLE-DAG: Decl[LocalVar]/Local/TypeRelation[Identical]: exact[#(Int, (Int, Int))#]; name=exact +// BROKEN_CONFORMANCE_ASSIGNABLE-DAG: Decl[InstanceVar]/Super/TypeRelation[Identical]: matches[#(Int, (Int, Int))#]; name=matches +// BROKEN_CONFORMANCE_ASSIGNABLE: End completions diff --git a/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp b/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp index 4a376bf277898..2fc29e21328b1 100644 --- a/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp +++ b/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp @@ -176,7 +176,6 @@ bool SourceKit::CodeCompletion::addCustomCompletions( } break; case CompletionKind::PostfixExprBeginning: - case CompletionKind::AssignmentRHS: case CompletionKind::CallArg: case CompletionKind::ReturnStmtExpr: case CompletionKind::YieldStmtExpr: From 4527711c52d7bd71f7b37fa54ba0b311acaec0a4 Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Tue, 17 Sep 2019 22:24:17 -0700 Subject: [PATCH 069/199] [SyntaxParses] Address memory issue in popTokenSyntax() Don't return reference for local temporary object rdar://problem/55421369 --- include/swift/Parse/SyntaxParsingContext.h | 2 +- lib/Parse/SyntaxParsingContext.cpp | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/swift/Parse/SyntaxParsingContext.h b/include/swift/Parse/SyntaxParsingContext.h index 2db8e6e9058c1..6df76bebca037 100644 --- a/include/swift/Parse/SyntaxParsingContext.h +++ b/include/swift/Parse/SyntaxParsingContext.h @@ -300,7 +300,7 @@ class alignas(1 << SyntaxAlignInBits) SyntaxParsingContext { return SyntaxNode(std::move(rawNode)); } - ParsedTokenSyntax &&popToken(); + ParsedTokenSyntax popToken(); /// Create a node using the tail of the collected parts. The number of parts /// is automatically determined from \c Kind. Node: limited number of \c Kind diff --git a/lib/Parse/SyntaxParsingContext.cpp b/lib/Parse/SyntaxParsingContext.cpp index 65cf131b10373..6cd6b507bf863 100644 --- a/lib/Parse/SyntaxParsingContext.cpp +++ b/lib/Parse/SyntaxParsingContext.cpp @@ -163,8 +163,9 @@ const SyntaxParsingContext *SyntaxParsingContext::getRoot() const { return Curr; } -ParsedTokenSyntax &&SyntaxParsingContext::popToken() { - return std::move(popIf().getValue()); +ParsedTokenSyntax SyntaxParsingContext::popToken() { + auto tok = popIf(); + return std::move(tok.getValue()); } /// Add Token with Trivia to the parts. From e40759b335bc789cc795e7698134c0bb289f5526 Mon Sep 17 00:00:00 2001 From: David Zarzycki Date: Wed, 18 Sep 2019 10:59:03 +0300 Subject: [PATCH 070/199] [SILOpt] NFC: fix -Wgnu-anonymous-struct warning --- .../Mandatory/DiagnoseStaticExclusivity.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp b/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp index 496cdf123ecde..f4f6247e4aad5 100644 --- a/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp +++ b/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp @@ -75,9 +75,9 @@ class RecordedAccess { union { BeginAccessInst *Inst; struct { - SILAccessKind ClosureAccessKind; - SILLocation ClosureAccessLoc; - }; + SILAccessKind AccessKind; + SILLocation AccessLoc; + } Closure; }; const IndexTrieNode *SubPath; @@ -89,7 +89,7 @@ class RecordedAccess { RecordedAccess(SILAccessKind ClosureAccessKind, SILLocation ClosureAccessLoc, const IndexTrieNode *SubPath) : RecordKind(RecordedAccessKind::NoescapeClosureCapture), - ClosureAccessKind(ClosureAccessKind), ClosureAccessLoc(ClosureAccessLoc), + Closure({ClosureAccessKind, ClosureAccessLoc}), SubPath(SubPath) { } RecordedAccessKind getRecordKind() const { @@ -106,7 +106,7 @@ class RecordedAccess { case RecordedAccessKind::BeginInstruction: return Inst->getAccessKind(); case RecordedAccessKind::NoescapeClosureCapture: - return ClosureAccessKind; + return Closure.AccessKind; }; llvm_unreachable("unhandled kind"); } @@ -116,7 +116,7 @@ class RecordedAccess { case RecordedAccessKind::BeginInstruction: return Inst->getLoc(); case RecordedAccessKind::NoescapeClosureCapture: - return ClosureAccessLoc; + return Closure.AccessLoc; }; llvm_unreachable("unhandled kind"); } From 1eaa767407b87f11ff37976ba3570953b83e0550 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Wed, 18 Sep 2019 08:27:37 -0700 Subject: [PATCH 071/199] [test] Run scale-tests on Linux too (#27223) It's likely that these were listed as "REQUIRES: OS=macosx" to not redundantly run them for iOS et al, but they don't take that long and so it's more useful for Linux devs to be able to run them locally if need be. Or to catch something that really is different on non-macOS. --- .../Sema/type_checker_perf/fast/array_of_tuples.swift.gyb | 1 - .../fast/more_specialized_generic_func.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar18360240.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar18699199.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar18724501.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar19181998.swift.gyb | 1 - .../type_checker_perf/fast/rdar19181998_nominals.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar19394804.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar19738292.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar19777895.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar20233198_any.swift.gyb | 1 - .../fast/rdar20233198_explicit_overloads.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar20233198_named.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar20233198_typed.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar20233198_weak.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar20818064.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar21070413.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar21328584.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar21720888.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar21930551.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar22532650.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar22626740.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar22810685.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar22836718.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar23327871.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar24543332.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar25866240.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar26939465.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar29025667.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar29358447.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar30213053.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar30389602.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar30729643.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar31563957.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar32999041.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar33292740.swift.gyb | 1 - .../Sema/type_checker_perf/fast/rdar40344044.swift.gyb | 1 - validation-test/Sema/type_checker_perf/fast/simd_add.gyb | 1 - .../Sema/type_checker_perf/slow/nil_coalescing.swift.gyb | 1 - .../Sema/type_checker_perf/slow/rdar20959612.swift.gyb | 1 - .../Sema/type_checker_perf/slow/rdar21198787.swift.gyb | 1 - .../Sema/type_checker_perf/slow/rdar27585838.swift.gyb | 1 - .../Sema/type_checker_perf/slow/rdar30596744_1.swift.gyb | 1 - .../Sema/type_checker_perf/slow/rdar30596744_2.swift.gyb | 1 - .../Sema/type_checker_perf/slow/rdar30606089.swift.gyb | 1 - .../Sema/type_checker_perf/slow/rdar33289839.swift.gyb | 1 - .../Sema/type_checker_perf/slow/rdar54580427.swift | 1 - .../Sema/type_checker_perf/slow/rdar54926602.swift | 1 - validation-test/compiler_scale/array_init.swift.gyb | 1 - validation-test/compiler_scale/bind_extension_decl.gyb | 1 - .../compiler_scale/bind_nested_extension_decl.gyb | 1 - .../compiler_scale/callee_analysis_invalidation.gyb | 1 - validation-test/compiler_scale/class_members.gyb | 1 - validation-test/compiler_scale/dynamic_lookup.gyb | 3 +-- validation-test/compiler_scale/dynamic_lookup_2.swift | 5 ++--- validation-test/compiler_scale/enum_indirect.gyb | 1 - validation-test/compiler_scale/enum_members.gyb | 1 - validation-test/compiler_scale/function_bodies.gyb | 1 - validation-test/compiler_scale/lazy_class_props.gyb | 1 - validation-test/compiler_scale/nominal_bodies.gyb | 1 - validation-test/compiler_scale/protocol_members.gyb | 1 - validation-test/compiler_scale/scale_neighbouring_getset.gyb | 1 - validation-test/compiler_scale/struct_members.gyb | 1 - validation-test/compiler_scale/struct_nested.gyb | 1 - validation-test/compiler_scale/used_conformances.gyb | 1 - .../compiler_scale/var_decl_usage_checker.swift.gyb | 1 - 66 files changed, 3 insertions(+), 69 deletions(-) diff --git a/validation-test/Sema/type_checker_perf/fast/array_of_tuples.swift.gyb b/validation-test/Sema/type_checker_perf/fast/array_of_tuples.swift.gyb index 9fe047a65a78d..c31af8247d186 100644 --- a/validation-test/Sema/type_checker_perf/fast/array_of_tuples.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/array_of_tuples.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 20 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts let a = [ diff --git a/validation-test/Sema/type_checker_perf/fast/more_specialized_generic_func.swift.gyb b/validation-test/Sema/type_checker_perf/fast/more_specialized_generic_func.swift.gyb index 1b9d3284119ec..7e758774daf08 100644 --- a/validation-test/Sema/type_checker_perf/fast/more_specialized_generic_func.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/more_specialized_generic_func.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 8 --end 40 --step 2 --select NumLeafScopes %s --expected-exit-code 0 -// REQUIRES: OS=macosx // REQUIRES: asserts protocol P { } diff --git a/validation-test/Sema/type_checker_perf/fast/rdar18360240.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar18360240.swift.gyb index 421324d06cb46..48bd229c1b3e9 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar18360240.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar18360240.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 2 --end 10 --step 2 --select NumConstraintScopes --polynomial-threshold 1.5 %s -// REQUIRES: OS=macosx // REQUIRES: asserts let empty: [Int] = [] diff --git a/validation-test/Sema/type_checker_perf/fast/rdar18699199.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar18699199.swift.gyb index 84870ae40e0b8..a180c0a87482b 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar18699199.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar18699199.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 10 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts public enum E { diff --git a/validation-test/Sema/type_checker_perf/fast/rdar18724501.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar18724501.swift.gyb index 9f619473296db..65e43aece7d41 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar18724501.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar18724501.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 5 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts typealias X = (Range, [Range]) diff --git a/validation-test/Sema/type_checker_perf/fast/rdar19181998.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar19181998.swift.gyb index 02e4f130c6507..7c23540f8ecff 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar19181998.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar19181998.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 30 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts public func test(_ fn: @escaping () -> Void) {} diff --git a/validation-test/Sema/type_checker_perf/fast/rdar19181998_nominals.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar19181998_nominals.swift.gyb index 2b776131439b8..dd996ad7e71bf 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar19181998_nominals.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar19181998_nominals.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 30 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts struct A { diff --git a/validation-test/Sema/type_checker_perf/fast/rdar19394804.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar19394804.swift.gyb index bb5bed290df89..1c48071767c4a 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar19394804.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar19394804.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 10 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts class rdar19394804 { diff --git a/validation-test/Sema/type_checker_perf/fast/rdar19738292.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar19738292.swift.gyb index 7a22deabc17b8..102d3f524114b 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar19738292.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar19738292.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 7 --end 12 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts // REQUIRES: rdar42650365 diff --git a/validation-test/Sema/type_checker_perf/fast/rdar19777895.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar19777895.swift.gyb index e5d2400121f7e..cc500050b1d38 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar19777895.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar19777895.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 3 --end 7 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts let _ = [ diff --git a/validation-test/Sema/type_checker_perf/fast/rdar20233198_any.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar20233198_any.swift.gyb index 04472f4778b64..7ec93bf0406bd 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar20233198_any.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar20233198_any.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 2 --end 6 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts let _ = (UInt8(0) diff --git a/validation-test/Sema/type_checker_perf/fast/rdar20233198_explicit_overloads.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar20233198_explicit_overloads.swift.gyb index 61f4779dfa8bd..3699c5b161880 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar20233198_explicit_overloads.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar20233198_explicit_overloads.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 2 --end 6 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts func overload(_ x: Int) -> Int { return x } diff --git a/validation-test/Sema/type_checker_perf/fast/rdar20233198_named.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar20233198_named.swift.gyb index 97f6a608707a5..2fe9fc07164ae 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar20233198_named.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar20233198_named.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 2 --end 6 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts let tuple = (UInt8(0) diff --git a/validation-test/Sema/type_checker_perf/fast/rdar20233198_typed.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar20233198_typed.swift.gyb index 9590ecbc84fd7..587a19993d326 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar20233198_typed.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar20233198_typed.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 2 --end 6 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts let tuple: (UInt8 diff --git a/validation-test/Sema/type_checker_perf/fast/rdar20233198_weak.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar20233198_weak.swift.gyb index e4e5b0d9fc883..91cfd66605da9 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar20233198_weak.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar20233198_weak.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 2 --end 6 --step 1 --select NumLeafScopes %s -Xfrontend=-verify -// REQUIRES: OS=macosx // REQUIRES: asserts weak var tuple = (UInt8(0) // expected-error {{'weak' may only be applied to}} diff --git a/validation-test/Sema/type_checker_perf/fast/rdar20818064.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar20818064.swift.gyb index ad2ee15ad57b2..a8384cf12eecf 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar20818064.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar20818064.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 20 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts typealias D = [String: Any] diff --git a/validation-test/Sema/type_checker_perf/fast/rdar21070413.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar21070413.swift.gyb index 28a70a5f0eab7..15bcf460ab30a 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar21070413.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar21070413.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 5 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts enum E: UInt { diff --git a/validation-test/Sema/type_checker_perf/fast/rdar21328584.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar21328584.swift.gyb index af07f9989aa8c..b2f38b6a691c4 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar21328584.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar21328584.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 5 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts struct S { diff --git a/validation-test/Sema/type_checker_perf/fast/rdar21720888.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar21720888.swift.gyb index 5c6d542cb3ecf..04e7a3f8c2767 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar21720888.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar21720888.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 10 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts _ = [ diff --git a/validation-test/Sema/type_checker_perf/fast/rdar21930551.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar21930551.swift.gyb index 23d0c00dc5bfb..95dc1cbbb589b 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar21930551.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar21930551.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 2 --end 6 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts let _ = [ diff --git a/validation-test/Sema/type_checker_perf/fast/rdar22532650.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar22532650.swift.gyb index 34d12f51a9d65..bf66800181a76 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar22532650.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar22532650.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 10 --end 15 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts _ = [ diff --git a/validation-test/Sema/type_checker_perf/fast/rdar22626740.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar22626740.swift.gyb index f30f317432b78..326a56eefa4c9 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar22626740.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar22626740.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 2 --end 7 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts var a: [UInt32] diff --git a/validation-test/Sema/type_checker_perf/fast/rdar22810685.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar22810685.swift.gyb index 7b930593549f2..5a2ce6c27b68f 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar22810685.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar22810685.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 5 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts let _: [String : (Int, Int) -> Bool] = [ diff --git a/validation-test/Sema/type_checker_perf/fast/rdar22836718.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar22836718.swift.gyb index bd6df51b63e91..02f62caa94f33 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar22836718.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar22836718.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 5 --end 10 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts let _ = [ diff --git a/validation-test/Sema/type_checker_perf/fast/rdar23327871.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar23327871.swift.gyb index 0b8e1057aecbc..e75507361c32b 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar23327871.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar23327871.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 8 --end 16 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts let i = 1 diff --git a/validation-test/Sema/type_checker_perf/fast/rdar24543332.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar24543332.swift.gyb index bfb508c61ccf1..f00b13adb87a2 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar24543332.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar24543332.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 5 --end 20 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts _ = [ diff --git a/validation-test/Sema/type_checker_perf/fast/rdar25866240.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar25866240.swift.gyb index 116a4e5c14c3e..3fd0109eb5f51 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar25866240.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar25866240.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 2 --end 10 --step 1 --select NumConstraintScopes %s -Xfrontend=-solver-disable-shrink -Xfrontend=-disable-constraint-solver-performance-hacks -Xfrontend=-solver-enable-operator-designated-types -// REQUIRES: OS=macosx // REQUIRES: asserts func f( diff --git a/validation-test/Sema/type_checker_perf/fast/rdar26939465.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar26939465.swift.gyb index 9d59f05d62b33..59a016b41df4a 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar26939465.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar26939465.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 2 --end 7 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts class NSNumber { diff --git a/validation-test/Sema/type_checker_perf/fast/rdar29025667.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar29025667.swift.gyb index 824a894e643cf..8fe1f3be07175 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar29025667.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar29025667.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 2 --end 7 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts let s: String? = nil diff --git a/validation-test/Sema/type_checker_perf/fast/rdar29358447.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar29358447.swift.gyb index a5d262ec37907..057403e1d69e4 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar29358447.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar29358447.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 0 --end 10000 --step 1000 --typecheck --select incrementConstraintsPerContractionCounter %s -// REQUIRES: OS=macosx // REQUIRES: asserts let _: [Int] = [ diff --git a/validation-test/Sema/type_checker_perf/fast/rdar30213053.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar30213053.swift.gyb index 094690423a9c8..81e53ce17b588 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar30213053.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar30213053.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 3 --end 7 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts let _: [Int: (Int, Int) -> Bool] = diff --git a/validation-test/Sema/type_checker_perf/fast/rdar30389602.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar30389602.swift.gyb index fb2c4ac6fe951..1e41ed86f63d6 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar30389602.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar30389602.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 2 --end 7 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts class C { diff --git a/validation-test/Sema/type_checker_perf/fast/rdar30729643.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar30729643.swift.gyb index ace10b9396395..c21fa6625bc19 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar30729643.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar30729643.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 15 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts enum X : String { diff --git a/validation-test/Sema/type_checker_perf/fast/rdar31563957.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar31563957.swift.gyb index fd9e67549224c..ee08646858f02 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar31563957.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar31563957.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 5 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts struct rdar33511986 { diff --git a/validation-test/Sema/type_checker_perf/fast/rdar32999041.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar32999041.swift.gyb index 3c564b351f1b9..86031343e2336 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar32999041.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar32999041.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 3 --end 8 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts // FIXME: https://bugs.swift.org/browse/SR-6997 // REQUIRES: SR6997 diff --git a/validation-test/Sema/type_checker_perf/fast/rdar33292740.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar33292740.swift.gyb index 14e6245f6bc6a..259fa08e212b2 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar33292740.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar33292740.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 2 --end 10 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts struct V3 { diff --git a/validation-test/Sema/type_checker_perf/fast/rdar40344044.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar40344044.swift.gyb index 30bf0d34e0159..0fbfba34390bf 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar40344044.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar40344044.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 3 --end 20 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts protocol P {} diff --git a/validation-test/Sema/type_checker_perf/fast/simd_add.gyb b/validation-test/Sema/type_checker_perf/fast/simd_add.gyb index 8bd1cf83e43ff..7b0f8ec1d1a38 100644 --- a/validation-test/Sema/type_checker_perf/fast/simd_add.gyb +++ b/validation-test/Sema/type_checker_perf/fast/simd_add.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 3 --end 7 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts func test(_ s: SIMD4, diff --git a/validation-test/Sema/type_checker_perf/slow/nil_coalescing.swift.gyb b/validation-test/Sema/type_checker_perf/slow/nil_coalescing.swift.gyb index 79138f905ccf3..d6349fdd4348e 100644 --- a/validation-test/Sema/type_checker_perf/slow/nil_coalescing.swift.gyb +++ b/validation-test/Sema/type_checker_perf/slow/nil_coalescing.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --invert-result --begin 1 --end 5 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts // REQUIRES: rdar38963783 diff --git a/validation-test/Sema/type_checker_perf/slow/rdar20959612.swift.gyb b/validation-test/Sema/type_checker_perf/slow/rdar20959612.swift.gyb index 669ebd69f7386..ad87ec01da757 100644 --- a/validation-test/Sema/type_checker_perf/slow/rdar20959612.swift.gyb +++ b/validation-test/Sema/type_checker_perf/slow/rdar20959612.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --invert-result --begin 3 --end 7 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts func curry { diff --git a/validation-test/compiler_scale/class_members.gyb b/validation-test/compiler_scale/class_members.gyb index 266834d2c4c1a..0c51b88398f3a 100644 --- a/validation-test/compiler_scale/class_members.gyb +++ b/validation-test/compiler_scale/class_members.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select NumDeclsValidated %s -// REQUIRES: OS=macosx // REQUIRES: asserts class Class${N} { diff --git a/validation-test/compiler_scale/dynamic_lookup.gyb b/validation-test/compiler_scale/dynamic_lookup.gyb index 07bcfc3409f03..64529f676bbce 100644 --- a/validation-test/compiler_scale/dynamic_lookup.gyb +++ b/validation-test/compiler_scale/dynamic_lookup.gyb @@ -1,5 +1,4 @@ -// RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select Sema.IsObjCRequest -Xfrontend=-disable-objc-attr-requires-foundation-module %s -// REQUIRES: OS=macosx +// RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select Sema.IsObjCRequest -Xfrontend=-enable-objc-interop -Xfrontend=-disable-objc-attr-requires-foundation-module %s // REQUIRES: asserts class C${N} { diff --git a/validation-test/compiler_scale/dynamic_lookup_2.swift b/validation-test/compiler_scale/dynamic_lookup_2.swift index f34acbd597efa..5c578cf71eee8 100644 --- a/validation-test/compiler_scale/dynamic_lookup_2.swift +++ b/validation-test/compiler_scale/dynamic_lookup_2.swift @@ -1,5 +1,4 @@ -// RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select NumIterableDeclContextParsed -Xfrontend=-disable-objc-attr-requires-foundation-module %s -// REQUIRES: OS=macosx +// RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select NumIterableDeclContextParsed -Xfrontend=-enable-objc-interop -Xfrontend=-disable-objc-attr-requires-foundation-module %s // REQUIRES: asserts // Dynamic member lookup should not force delayed parsing of structs, enums or protocol @@ -16,4 +15,4 @@ class C { func f${N}(a: AnyObject) { a.isObjCMember!() -} \ No newline at end of file +} diff --git a/validation-test/compiler_scale/enum_indirect.gyb b/validation-test/compiler_scale/enum_indirect.gyb index 49990d6099bb7..7e6a8b0ae01e4 100644 --- a/validation-test/compiler_scale/enum_indirect.gyb +++ b/validation-test/compiler_scale/enum_indirect.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select NumDeclsValidated %s -// REQUIRES: OS=macosx // REQUIRES: asserts indirect enum Enum${N} { diff --git a/validation-test/compiler_scale/enum_members.gyb b/validation-test/compiler_scale/enum_members.gyb index 5848eb34cfaef..9c0fc0020dcc3 100644 --- a/validation-test/compiler_scale/enum_members.gyb +++ b/validation-test/compiler_scale/enum_members.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select NumDeclsValidated %s -// REQUIRES: OS=macosx // REQUIRES: asserts enum Enum${N} { diff --git a/validation-test/compiler_scale/function_bodies.gyb b/validation-test/compiler_scale/function_bodies.gyb index 4cccbbbb537fe..4abcd4136c1ee 100644 --- a/validation-test/compiler_scale/function_bodies.gyb +++ b/validation-test/compiler_scale/function_bodies.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select NumFunctionsParsed %s -// REQUIRES: OS=macosx // REQUIRES: asserts func method${N}() {} diff --git a/validation-test/compiler_scale/lazy_class_props.gyb b/validation-test/compiler_scale/lazy_class_props.gyb index b16535877eac7..cef23e2eb5b8b 100644 --- a/validation-test/compiler_scale/lazy_class_props.gyb +++ b/validation-test/compiler_scale/lazy_class_props.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test -O --begin 5 --end 21 --step 5 --select StoredPropertiesRequest %s -// REQUIRES: OS=macosx // REQUIRES: asserts // // Single file with many stored properties. diff --git a/validation-test/compiler_scale/nominal_bodies.gyb b/validation-test/compiler_scale/nominal_bodies.gyb index 9cb25a3b65f02..5a0aa10dc1c04 100644 --- a/validation-test/compiler_scale/nominal_bodies.gyb +++ b/validation-test/compiler_scale/nominal_bodies.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select NumIterableDeclContextParsed %s -// REQUIRES: OS=macosx // REQUIRES: asserts struct S${N} {} diff --git a/validation-test/compiler_scale/protocol_members.gyb b/validation-test/compiler_scale/protocol_members.gyb index 8553ea03b9047..b7cb34bb736ad 100644 --- a/validation-test/compiler_scale/protocol_members.gyb +++ b/validation-test/compiler_scale/protocol_members.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select NumDeclsValidated %s -// REQUIRES: OS=macosx // REQUIRES: asserts protocol Protocol${N} { diff --git a/validation-test/compiler_scale/scale_neighbouring_getset.gyb b/validation-test/compiler_scale/scale_neighbouring_getset.gyb index 5b15ae82ae1de..332016b767156 100644 --- a/validation-test/compiler_scale/scale_neighbouring_getset.gyb +++ b/validation-test/compiler_scale/scale_neighbouring_getset.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select NumFunctionsTypechecked %s -// REQUIRES: OS=macosx // REQUIRES: asserts struct Struct${N} { diff --git a/validation-test/compiler_scale/struct_members.gyb b/validation-test/compiler_scale/struct_members.gyb index 1a8e530917fef..cc91e3117d82f 100644 --- a/validation-test/compiler_scale/struct_members.gyb +++ b/validation-test/compiler_scale/struct_members.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select NumDeclsValidated %s -// REQUIRES: OS=macosx // REQUIRES: asserts struct Struct${N} { diff --git a/validation-test/compiler_scale/struct_nested.gyb b/validation-test/compiler_scale/struct_nested.gyb index 1ee84d2d98cd9..581560371ab0b 100644 --- a/validation-test/compiler_scale/struct_nested.gyb +++ b/validation-test/compiler_scale/struct_nested.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select NumDeclsValidated %s -// REQUIRES: OS=macosx // REQUIRES: asserts struct Struct${N} { diff --git a/validation-test/compiler_scale/used_conformances.gyb b/validation-test/compiler_scale/used_conformances.gyb index 333cb8224f9fe..70a6f2ed46196 100644 --- a/validation-test/compiler_scale/used_conformances.gyb +++ b/validation-test/compiler_scale/used_conformances.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select NumDeclsValidated %s -// REQUIRES: OS=macosx // REQUIRES: asserts struct Generic${N} {} diff --git a/validation-test/compiler_scale/var_decl_usage_checker.swift.gyb b/validation-test/compiler_scale/var_decl_usage_checker.swift.gyb index 158eb2f333fd0..2f6d1937470ac 100644 --- a/validation-test/compiler_scale/var_decl_usage_checker.swift.gyb +++ b/validation-test/compiler_scale/var_decl_usage_checker.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 5 --step 1 --select VarDeclUsageCheckerExprVisits %s -// REQUIRES: OS=macosx // REQUIRES: asserts protocol Proto {} From 2255e81ad0e12472c31fbf3b01231321a35881e6 Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Wed, 18 Sep 2019 10:30:36 -0700 Subject: [PATCH 072/199] [NFC] Replacing potentially confusing phrase "memory allocation promotion" --- docs/SIL.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/SIL.rst b/docs/SIL.rst index 701a94909c240..3e159437bfa44 100644 --- a/docs/SIL.rst +++ b/docs/SIL.rst @@ -17,8 +17,10 @@ the Swift programming language. SIL accommodates the following use cases: such as definitive initialization of variables and constructors, code reachability, switch coverage. - High-level optimization passes, including retain/release optimization, - dynamic method devirtualization, closure inlining, memory allocation promotion, - and generic function instantiation. + dynamic method devirtualization, closure inlining, promoting heap allocations + to stack allocations, promoting stack allocations to SSA registers, scalar + replacement of aggregates (splitting aggregate allocations into multiple + smaller allocations), and generic function instantiation. - A stable distribution format that can be used to distribute "fragile" inlineable or generic code with Swift library modules, to be optimized into client binaries. From 61fd4b143153aca89ef68617f45022d0bd1722d2 Mon Sep 17 00:00:00 2001 From: Ravi Kandhadai Date: Mon, 16 Sep 2019 11:59:16 -0700 Subject: [PATCH 073/199] [OSLog][Test] Update the new oslog overlay implementation to use @_semantics("constant_evaluable") annotation to denote constant evaluable functions. Add a test suite that uses the sil-opt pass ConstantEvaluableSubsetChecker.cpp to check the constant evaluability of function in the OSLog overlay. --- include/swift/AST/DiagnosticsSIL.def | 11 ++-- lib/SIL/SILConstants.cpp | 6 +-- .../Mandatory/OSLogOptimization.cpp | 2 +- .../ConstantEvaluableSubsetChecker.cpp | 46 ++++++++++++++--- lib/SILOptimizer/Utils/ConstExpr.cpp | 17 ++++--- stdlib/private/OSLog/OSLogIntegerTypes.swift | 4 +- stdlib/private/OSLog/OSLogMessage.swift | 21 ++++---- stdlib/private/OSLog/OSLogStringTypes.swift | 4 +- .../OSLogConstantEvaluableTest.swift | 51 +++++++++++++++++++ test/SILOptimizer/constant_evaluator_test.sil | 2 +- .../pound_assert_test_recursive.swift | 2 +- 11 files changed, 130 insertions(+), 36 deletions(-) create mode 100644 test/SILOptimizer/OSLogConstantEvaluableTest.swift diff --git a/include/swift/AST/DiagnosticsSIL.def b/include/swift/AST/DiagnosticsSIL.def index 66f04071c3d35..8abc49e942b74 100644 --- a/include/swift/AST/DiagnosticsSIL.def +++ b/include/swift/AST/DiagnosticsSIL.def @@ -402,9 +402,11 @@ NOTE(constexpr_unsupported_instruction_found, none, NOTE(constexpr_unsupported_instruction_found_here,none, "operation" "%select{| used by this call is}0 not supported by the evaluator", (bool)) -NOTE(constexpr_unknown_function_called, none, - "encountered call to '%0' whose body is not available", (StringRef)) -NOTE(constexpr_unknown_function_called_here, none, +NOTE(constexpr_found_callee_with_no_body, none, + "encountered call to '%0' whose body is not available. " + "Imported functions must be marked '@inlinable' to constant evaluate.", + (StringRef)) +NOTE(constexpr_callee_with_no_body, none, "%select{|calls a }0function whose body is not available", (bool)) NOTE(constexpr_untracked_sil_value_use_found, none, @@ -428,7 +430,10 @@ NOTE(constexpr_returned_by_unevaluated_instruction,none, "return value of an unevaluated instruction is not a constant", ()) NOTE(constexpr_mutated_by_unevaluated_instruction,none, "value mutable by an " "unevaluated instruction is not a constant", ()) + ERROR(not_constant_evaluable, none, "not constant evaluable", ()) +ERROR(constexpr_imported_func_not_onone, none, "imported constant evaluable " + "function '%0' must be annotated '@_optimize(none)'", (StringRef)) ERROR(non_physical_addressof,none, "addressof only works with purely physical lvalues; " diff --git a/lib/SIL/SILConstants.cpp b/lib/SIL/SILConstants.cpp index 711bee1a375c0..235b78601cd9d 100644 --- a/lib/SIL/SILConstants.cpp +++ b/lib/SIL/SILConstants.cpp @@ -20,7 +20,7 @@ using namespace swift; namespace swift { llvm::cl::opt - ConstExprLimit("constexpr-limit", llvm::cl::init(512), + ConstExprLimit("constexpr-limit", llvm::cl::init(1024), llvm::cl::desc("Number of instructions interpreted in a" " constexpr function")); } @@ -711,10 +711,10 @@ void SymbolicValue::emitUnknownDiagnosticNotes(SILLocation fallbackLoc) { SILFunction *callee = unknownReason.getCalleeWithoutImplmentation(); std::string demangledCalleeName = Demangle::demangleSymbolAsString(callee->getName()); - diagnose(ctx, diagLoc, diag::constexpr_unknown_function_called, + diagnose(ctx, diagLoc, diag::constexpr_found_callee_with_no_body, StringRef(demangledCalleeName)); if (emitTriggerLocInDiag) - diagnose(ctx, triggerLoc, diag::constexpr_unknown_function_called_here, + diagnose(ctx, triggerLoc, diag::constexpr_callee_with_no_body, triggerLocSkipsInternalLocs); return; } diff --git a/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp b/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp index 481ccc7105f8e..8f4dd787d5bbf 100644 --- a/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp +++ b/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp @@ -249,7 +249,7 @@ static bool shouldAttemptEvaluation(SILInstruction *inst) { return false; return calleeFun->hasSemanticsAttrThatStartsWith("string.") || - calleeFun->hasSemanticsAttrThatStartsWith("oslog."); + calleeFun->hasSemanticsAttr("constant_evaluable"); } /// Skip or evaluate the given instruction based on the evaluation policy and diff --git a/lib/SILOptimizer/UtilityPasses/ConstantEvaluableSubsetChecker.cpp b/lib/SILOptimizer/UtilityPasses/ConstantEvaluableSubsetChecker.cpp index 953877c292668..c8af3a51c4688 100644 --- a/lib/SILOptimizer/UtilityPasses/ConstantEvaluableSubsetChecker.cpp +++ b/lib/SILOptimizer/UtilityPasses/ConstantEvaluableSubsetChecker.cpp @@ -65,6 +65,7 @@ class ConstantEvaluableSubsetChecker : public SILModuleTransform { SymbolicValueBumpAllocator allocator; ConstExprStepEvaluator stepEvaluator(allocator, fun, /*trackCallees*/ true); + bool previousEvaluationHadFatalError = false; for (auto currI = fun->getEntryBlock()->begin();;) { auto *inst = &(*currI); @@ -72,6 +73,10 @@ class ConstantEvaluableSubsetChecker : public SILModuleTransform { if (isa(inst)) break; + assert(!previousEvaluationHadFatalError && + "cannot continue evaluation of test driver as previous call " + "resulted in non-skippable evaluation error."); + auto *applyInst = dyn_cast(inst); SILFunction *callee = nullptr; if (applyInst) { @@ -85,7 +90,11 @@ class ConstantEvaluableSubsetChecker : public SILModuleTransform { !callee->hasSemanticsAttr(constantEvaluableSemanticsAttr)) { std::tie(nextInstOpt, errorVal) = stepEvaluator.tryEvaluateOrElseMakeEffectsNonConstant(currI); - assert(nextInstOpt && "non-constant control flow in the test driver"); + if (!nextInstOpt) { + // This indicates an error in the test driver. + errorVal->emitUnknownDiagnosticNotes(inst->getLoc()); + assert(false && "non-constant control flow in the test driver"); + } currI = nextInstOpt.getValue(); continue; } @@ -101,17 +110,40 @@ class ConstantEvaluableSubsetChecker : public SILModuleTransform { errorVal->emitUnknownDiagnosticNotes(inst->getLoc()); } - if (!nextInstOpt) { - break; // This instruction should be the end of the test driver. + if (nextInstOpt) { + currI = nextInstOpt.getValue(); + continue; } - currI = nextInstOpt.getValue(); + + // Here, a non-skippable error like "instruction-limit exceeded" has been + // encountered during evaluation. Proceed to the next instruction but + // ensure that an assertion failure occurs if there is any instruction + // to evaluate after this instruction. + ++currI; + previousEvaluationHadFatalError = true; } - // Record functions that were called during this evaluation to detect - // whether the test drivers in the SILModule cover all function annotated - // as "constant_evaluable". + // For every function seen during the evaluation of this constant evaluable + // function: + // 1. Record it so as to detect whether the test drivers in the SILModule + // cover all function annotated as "constant_evaluable". + // + // 2. If the callee is annotated as constant_evaluable and is imported from + // a different Swift module (other than stdlib), check that the function is + // marked as Onone. Otherwise, it could have been optimized, which will + // break constant evaluability. for (SILFunction *callee : stepEvaluator.getFuncsCalledDuringEvaluation()) { evaluatedFunctions.insert(callee); + + SILModule &calleeModule = callee->getModule(); + if (callee->isAvailableExternally() && + callee->hasSemanticsAttr(constantEvaluableSemanticsAttr) && + callee->getOptimizationMode() != OptimizationMode::NoOptimization) { + diagnose(calleeModule.getASTContext(), + callee->getLocation().getSourceLoc(), + diag::constexpr_imported_func_not_onone, + demangleSymbolName(callee->getName())); + } } } diff --git a/lib/SILOptimizer/Utils/ConstExpr.cpp b/lib/SILOptimizer/Utils/ConstExpr.cpp index ecc0677436ee7..71a36b29e807c 100644 --- a/lib/SILOptimizer/Utils/ConstExpr.cpp +++ b/lib/SILOptimizer/Utils/ConstExpr.cpp @@ -1534,8 +1534,17 @@ ConstExprFunctionState::evaluateInstructionAndGetNext( assert(value.getKind() == SymbolicValue::Enum || value.getKind() == SymbolicValue::EnumWithPayload); - auto *caseBB = switchInst->getCaseDestination(value.getEnumValue()); + SILBasicBlock *caseBB = + switchInst->getCaseDestination(value.getEnumValue()); + if (caseBB->getNumArguments() == 0) + return {caseBB->begin(), None}; + // Set up the arguments. + + // When there are multiple payload components, they form a single + // tuple-typed argument. + assert(caseBB->getNumArguments() == 1); + if (caseBB->getParent()->hasOwnership() && switchInst->getDefaultBBOrNull() == caseBB) { // If we are visiting the default block and we are in ossa, then we may @@ -1545,13 +1554,7 @@ ConstExprFunctionState::evaluateInstructionAndGetNext( return {caseBB->begin(), None}; } - if (caseBB->getNumArguments() == 0) - return {caseBB->begin(), None}; - assert(value.getKind() == SymbolicValue::EnumWithPayload); - // When there are multiple payload components, they form a single - // tuple-typed argument. - assert(caseBB->getNumArguments() == 1); auto argument = value.getEnumPayloadValue(); assert(argument.isConstant()); setValue(caseBB->getArgument(0), argument); diff --git a/stdlib/private/OSLog/OSLogIntegerTypes.swift b/stdlib/private/OSLog/OSLogIntegerTypes.swift index 900c212671d1f..53b4c60004fdb 100644 --- a/stdlib/private/OSLog/OSLogIntegerTypes.swift +++ b/stdlib/private/OSLog/OSLogIntegerTypes.swift @@ -106,7 +106,7 @@ extension OSLogInterpolation { /// This function must be constant evaluable and all its arguments /// must be known at compile time. @inlinable - @_semantics("oslog.interpolation.getFormatSpecifier") + @_semantics("constant_evaluable") @_effects(readonly) @_optimize(none) internal func getIntegerFormatSpecifier( @@ -150,7 +150,7 @@ extension OSLogArguments { /// Return the number of bytes needed for serializing an integer argument as /// specified by os_log. This function must be constant evaluable. @inlinable -@_semantics("oslog.integers.sizeForEncoding") +@_semantics("constant_evaluable") @_effects(readonly) @_optimize(none) internal func sizeForEncoding( diff --git a/stdlib/private/OSLog/OSLogMessage.swift b/stdlib/private/OSLog/OSLogMessage.swift index 9c7cacab893db..ed84469f916fa 100644 --- a/stdlib/private/OSLog/OSLogMessage.swift +++ b/stdlib/private/OSLog/OSLogMessage.swift @@ -95,7 +95,7 @@ public struct OSLogInterpolation : StringInterpolationProtocol { /// argument header. The first two bits are used to indicate privacy and /// the other two are reserved. @usableFromInline - @_frozen + @frozen internal enum ArgumentFlag { case privateFlag case publicFlag @@ -117,7 +117,7 @@ public struct OSLogInterpolation : StringInterpolationProtocol { /// (Note that an auto-generated rawValue is not constant evaluable because /// it cannot be annotated so.) @usableFromInline - @_frozen + @frozen internal enum ArgumentType { case scalar, count, string, pointer, object @@ -147,7 +147,7 @@ public struct OSLogInterpolation : StringInterpolationProtocol { /// mask indicate whether there is an argument that is private, and whether /// there is an argument that is non-scalar: String, NSObject or Pointer. @usableFromInline - @_frozen + @frozen internal enum PreambleBitMask { case privateBitMask case nonScalarBitMask @@ -195,7 +195,7 @@ public struct OSLogInterpolation : StringInterpolationProtocol { /// An internal initializer that should be used only when there are no /// interpolated expressions. This function must be constant evaluable. @inlinable - @_semantics("oslog.interpolation.init") + @_semantics("constant_evaluable") @_optimize(none) internal init() { formatString = "" @@ -216,7 +216,7 @@ public struct OSLogInterpolation : StringInterpolationProtocol { /// Return true if and only if the parameter is .private. /// This function must be constant evaluable. @inlinable - @_semantics("oslog.interpolation.isPrivate") + @_semantics("constant_evaluable") @_effects(readonly) @_optimize(none) internal func isPrivate(_ privacy: Privacy) -> Bool { @@ -233,7 +233,7 @@ public struct OSLogInterpolation : StringInterpolationProtocol { /// of the header byte, respectively. /// This function should be constant evaluable. @inlinable - @_semantics("oslog.interpolation.getArgumentHeader") + @_semantics("constant_evaluable") @_effects(readonly) @_optimize(none) internal func getArgumentHeader( @@ -248,7 +248,7 @@ public struct OSLogInterpolation : StringInterpolationProtocol { /// Compute the new preamble based whether the current argument is private /// or not. This function must be constant evaluable. @inlinable - @_semantics("oslog.interpolation.getUpdatedPreamble") + @_semantics("constant_evaluable") @_effects(readonly) @_optimize(none) internal func getUpdatedPreamble( @@ -268,7 +268,8 @@ public struct OSLogInterpolation : StringInterpolationProtocol { extension String { /// Replace all percents "%" in the string by "%%" so that the string can be - /// interpreted as a C format string. + /// interpreted as a C format string. This function is constant evaluable + /// and its semantics is modeled within the evaluator. public var percentEscapedString: String { @_semantics("string.escapePercent.get") @_effects(readonly) @@ -292,6 +293,7 @@ public struct OSLogMessage : @inlinable @_optimize(none) @_semantics("oslog.message.init_interpolation") + @_semantics("constant_evaluable") public init(stringInterpolation: OSLogInterpolation) { self.interpolation = stringInterpolation } @@ -301,6 +303,7 @@ public struct OSLogMessage : @inlinable @_optimize(none) @_semantics("oslog.message.init_stringliteral") + @_semantics("constant_evaluable") public init(stringLiteral value: String) { var s = OSLogInterpolation() s.appendLiteral(value) @@ -332,7 +335,7 @@ internal struct OSLogArguments { /// This function must be constant evaluable. @inlinable - @_semantics("oslog.arguments.init_empty") + @_semantics("constant_evaluable") @_optimize(none) internal init() { argumentClosures = nil diff --git a/stdlib/private/OSLog/OSLogStringTypes.swift b/stdlib/private/OSLog/OSLogStringTypes.swift index 46ce0a5bea8f5..a423e6295e59f 100644 --- a/stdlib/private/OSLog/OSLogStringTypes.swift +++ b/stdlib/private/OSLog/OSLogStringTypes.swift @@ -74,7 +74,7 @@ extension OSLogInterpolation { /// This function must be constant evaluable and all its arguments /// must be known at compile time. @inlinable - @_semantics("oslog.interpolation.getFormatSpecifier") + @_semantics("constant_evaluable") @_effects(readonly) @_optimize(none) internal func getStringFormatSpecifier(_ isPrivate: Bool) -> String { @@ -102,7 +102,7 @@ extension OSLogArguments { @inlinable @_optimize(none) @_effects(readonly) -@_semantics("oslog.string.sizeForEncoding") +@_semantics("constant_evaluable") internal func sizeForEncoding() -> Int { return Int.bitWidth &>> logBitsPerByte } diff --git a/test/SILOptimizer/OSLogConstantEvaluableTest.swift b/test/SILOptimizer/OSLogConstantEvaluableTest.swift new file mode 100644 index 0000000000000..c96985ab79e92 --- /dev/null +++ b/test/SILOptimizer/OSLogConstantEvaluableTest.swift @@ -0,0 +1,51 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-silgen -primary-file %s -o %t/OSLogConstantEvaluableTest_silgen.sil +// +// Run the (mandatory) passes on which constant evaluator depends, and run the +// constant evaluator on the SIL produced after the dependent passes are run. +// +// RUN: %target-sil-opt -silgen-cleanup -raw-sil-inst-lowering -allocbox-to-stack -mandatory-inlining -constexpr-limit 1024 -test-constant-evaluable-subset %t/OSLogConstantEvaluableTest_silgen.sil > %t/OSLogConstantEvaluableTest.sil 2> %t/error-output +// +// RUN: %FileCheck %s < %t/error-output +// +// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos + +// Test that the functions defined in the OSLogPrototype overlay annotated as +// constant evaluable are so (with the constexpr-limit defined above). +// This test is meant to catch regressions in the OSLog overlay implementation +// affecting the constant evaluability of functions that are expected to be so. + +import OSLogPrototype + +// CHECK-LABEL: @init(stringLiteral: String) -> OSLogMessage +// CHECK-NOT: error: +@_semantics("test_driver") +func osLogMessageStringLiteralInitTest() -> OSLogMessage { + return "A string literal" +} + +// CHECK-LABEL: @isPrivate(Privacy) -> Bool +// CHECK-NOT: error: +// CHECK-LABEL: @getIntegerFormatSpecifier(A.Type, IntFormat, Bool) -> String +// CHECK-NOT: error: +// CHECK-LABEL: @sizeForEncoding(A.Type) -> Int +// CHECK-NOT: error: +// CHECK-LABEL: @getArgumentHeader(isPrivate: Bool, type: ArgumentType) -> UInt8 +// CHECK-NOT: error: +// CHECK-LABEL: @getUpdatedPreamble(isPrivate: Bool, isScalar: Bool) -> UInt8 +// CHECK-NOT: error: +// CHECK-LABEL: @init(stringInterpolation: OSLogInterpolation) -> OSLogMessage +// CHECK-NOT: error: +@_semantics("test_driver") +func intValueInterpolationTest() -> OSLogMessage { + return "An integer value \(10)" +} + +// CHECK-LABEL: @getStringFormatSpecifier(Bool) -> String +// CHECK-NOT: error: +// CHECK-LABEL: @sizeForEncoding() -> Int +// CHECK-NOT: error: +@_semantics("test_driver") +func stringValueInterpolationTest() -> OSLogMessage { + return "A string value \("xyz")" +} diff --git a/test/SILOptimizer/constant_evaluator_test.sil b/test/SILOptimizer/constant_evaluator_test.sil index e0029995a6e01..3f0fc690d4601 100644 --- a/test/SILOptimizer/constant_evaluator_test.sil +++ b/test/SILOptimizer/constant_evaluator_test.sil @@ -279,7 +279,7 @@ bb0: %0 = integer_literal $Builtin.Int64, -5 %2 = function_ref @factorial : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 %3 = apply %2(%0) : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 - // CHECK: {{.*}}:[[@LINE-1]]:{{.*}}: note: exceeded instruction limit: 512 when evaluating the expression at compile time + // CHECK: {{.*}}:[[@LINE-1]]:{{.*}}: note: exceeded instruction limit: {{.*}} when evaluating the expression at compile time // CHECK: {{.*}}: note: limit exceeded here return %3 : $Builtin.Int64 } diff --git a/test/SILOptimizer/pound_assert_test_recursive.swift b/test/SILOptimizer/pound_assert_test_recursive.swift index 8f99385be1300..e62ef5fceefc0 100644 --- a/test/SILOptimizer/pound_assert_test_recursive.swift +++ b/test/SILOptimizer/pound_assert_test_recursive.swift @@ -10,7 +10,7 @@ // match what we actually want. // CHECK: error: #assert condition not constant -// CHECK: note: exceeded instruction limit: 512 when evaluating the expression at compile time +// CHECK: note: exceeded instruction limit: {{.*}} when evaluating the expression at compile time // CHECK: limit exceeded here func recursive(a: Int) -> Int { return a == 0 ? 0 : recursive(a: a-1) From 4f6951c42fb624e1d59b390250cc8a4fe8767262 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 18 Sep 2019 10:44:50 -0700 Subject: [PATCH 074/199] Change a cycle condition Not having the generic signature is the real culprit here. --- include/swift/AST/TypeCheckRequests.h | 8 +++++++- lib/AST/TypeCheckRequests.cpp | 20 ++++++++++++++++++++ lib/Sema/TypeCheckType.cpp | 2 +- test/Generics/generic_types.swift | 2 ++ test/decl/protocol/req/recursion.swift | 4 ++-- 5 files changed, 32 insertions(+), 4 deletions(-) diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 2917508499a62..ddf92263f982d 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -434,6 +434,9 @@ class RequirementRequest : // Source location SourceLoc getNearestLoc() const; + // Cycle handling. + void noteCycleStep(DiagnosticEngine &diags) const; + // Separate caching. bool isCached() const; Optional getCachedResult() const; @@ -1120,6 +1123,9 @@ class InferredGenericSignatureRequest : SourceLoc getNearestLoc() const { return SourceLoc(); } + + // Cycle handling. + void noteCycleStep(DiagnosticEngine &diags) const; }; void simple_display(llvm::raw_ostream &out, const TypeLoc source); @@ -1174,7 +1180,7 @@ class GenericSignatureRequest : llvm::Expected evaluate(Evaluator &evaluator, GenericContext *value) const; -public: +public: // Separate caching. bool isCached() const { return true; } Optional getCachedResult() const; diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index 2a1cab27fabb7..f8b17a4db6ea7 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -364,6 +364,14 @@ SourceLoc RequirementRequest::getNearestLoc() const { return owner.getLoc(); } +void RequirementRequest::noteCycleStep(DiagnosticEngine &diags) const { + // For now, the GSB does a better job of describing the exact structure of + // the cycle. + // + // FIXME: We should consider merging the circularity handling the GSB does + // into this request. See rdar://55263708 +} + MutableArrayRef WhereClauseOwner::getRequirements() const { if (auto genericParams = source.dyn_cast()) { return genericParams->getRequirements(); @@ -823,6 +831,18 @@ void GenericSignatureRequest::cacheResult(GenericSignature *value) const { GC->GenericSigAndBit.setPointerAndInt(value, true); } +//----------------------------------------------------------------------------// +// GenericSignatureRequest computation. +//----------------------------------------------------------------------------// + +void InferredGenericSignatureRequest::noteCycleStep(DiagnosticEngine &d) const { + // For now, the GSB does a better job of describing the exact structure of + // the cycle. + // + // FIXME: We should consider merging the circularity handling the GSB does + // into this request. See rdar://55263708 +} + //----------------------------------------------------------------------------// // IsImplicitlyUnwrappedOptionalRequest computation. //----------------------------------------------------------------------------// diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 8d8911c9dfbb8..4498e55e9ccca 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -768,7 +768,7 @@ Type TypeChecker::applyGenericArguments(Type type, } // FIXME: More principled handling of circularity. - if (!genericDecl->hasValidSignature()) { + if (!genericDecl->getGenericSignature()) { diags.diagnose(loc, diag::recursive_decl_reference, genericDecl->getDescriptiveKind(), genericDecl->getName()); genericDecl->diagnose(diag::kind_declared_here, DescriptiveDeclKind::Type); diff --git a/test/Generics/generic_types.swift b/test/Generics/generic_types.swift index 33e6aa36eb6bc..54af5d8858056 100644 --- a/test/Generics/generic_types.swift +++ b/test/Generics/generic_types.swift @@ -230,6 +230,8 @@ class Top {} class Bottom> {} // expected-error@-1 {{generic class 'Bottom' references itself}} // expected-note@-2 {{type declared here}} +// expected-error@-3 {{circular reference}} +// expected-note@-4 {{through reference here}} // Invalid inheritance clause diff --git a/test/decl/protocol/req/recursion.swift b/test/decl/protocol/req/recursion.swift index 12af9d8cdf803..0ad3d7b01f69e 100644 --- a/test/decl/protocol/req/recursion.swift +++ b/test/decl/protocol/req/recursion.swift @@ -43,7 +43,7 @@ public protocol P { associatedtype T } -public struct S where A.T == S { +public struct S where A.T == S { // expected-error {{circular reference}} // expected-note@-1 {{type declared here}} // expected-error@-2 {{generic struct 'S' references itself}} func f(a: A.T) { @@ -71,7 +71,7 @@ protocol PI { associatedtype T : I } -struct SI : I where A : I, A.T == SI { +struct SI : I where A : I, A.T == SI { // expected-error {{circular reference}} // expected-note@-1 {{type declared here}} // expected-error@-2 {{generic struct 'SI' references itself}} func ggg(t: T.Type) -> T { From 67c668200a271eb76aa77ba5b279b860a5e8b275 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 17 Sep 2019 17:07:15 -0400 Subject: [PATCH 075/199] Sema: Compute and store captures for default argument expressions --- include/swift/AST/Decl.h | 8 +++++ lib/AST/Decl.cpp | 5 +++ lib/Sema/TypeCheckCaptures.cpp | 62 +++++++++++++++++++++------------ test/SILGen/capture_order.swift | 4 +-- 4 files changed, 55 insertions(+), 24 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 38e336135ebaf..11c8c57d5155c 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -5164,6 +5164,7 @@ class ParamDecl : public VarDecl { PointerUnion DefaultArg; Initializer *InitContext = nullptr; StringRef StringRepresentation; + CaptureInfo Captures; }; enum class Flags : uint8_t { @@ -5249,6 +5250,13 @@ class ParamDecl : public VarDecl { void setDefaultArgumentInitContext(Initializer *initContext); + const CaptureInfo &getDefaultArgumentCaptureInfo() const { + assert(DefaultValueAndFlags.getPointer()); + return DefaultValueAndFlags.getPointer()->Captures; + } + + void setDefaultArgumentCaptureInfo(const CaptureInfo &captures); + /// Extracts the text of the default argument attached to the provided /// ParamDecl, removing all inactive #if clauses and providing only the /// text of active #if clauses. diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index e878ce36d396a..e57ba64850c88 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -5866,6 +5866,11 @@ void ParamDecl::setDefaultArgumentInitContext(Initializer *initContext) { DefaultValueAndFlags.getPointer()->InitContext = initContext; } +void ParamDecl::setDefaultArgumentCaptureInfo(const CaptureInfo &captures) { + assert(DefaultValueAndFlags.getPointer()); + DefaultValueAndFlags.getPointer()->Captures = captures; +} + /// Return nullptr if there is no property wrapper Expr *swift::findOriginalPropertyWrapperInitialValue(VarDecl *var, Expr *init) { diff --git a/lib/Sema/TypeCheckCaptures.cpp b/lib/Sema/TypeCheckCaptures.cpp index c376ec6c91a8d..2ea6e7aad875f 100644 --- a/lib/Sema/TypeCheckCaptures.cpp +++ b/lib/Sema/TypeCheckCaptures.cpp @@ -325,11 +325,8 @@ class FindCapturedVars : public ASTWalker { return { false, DRE }; } - void propagateCaptures(AnyFunctionRef innerClosure, SourceLoc captureLoc) { - TypeChecker::computeCaptures(innerClosure); - - auto &captureInfo = innerClosure.getCaptureInfo(); - + void propagateCaptures(const CaptureInfo &captureInfo, + SourceLoc loc) { for (auto capture : captureInfo.getCaptures()) { // If the decl was captured from us, it isn't captured *by* us. if (capture.getDecl()->getDeclContext() == CurDC) @@ -347,18 +344,19 @@ class FindCapturedVars : public ASTWalker { if (!NoEscape) Flags &= ~CapturedValue::IsNoEscape; - addCapture(CapturedValue(capture.getDecl(), Flags, captureLoc)); + addCapture(CapturedValue(capture.getDecl(), Flags, capture.getLoc())); } if (GenericParamCaptureLoc.isInvalid()) if (captureInfo.hasGenericParamCaptures()) - GenericParamCaptureLoc = innerClosure.getLoc(); + GenericParamCaptureLoc = loc; - if (DynamicSelfCaptureLoc.isInvalid()) + if (DynamicSelfCaptureLoc.isInvalid()) { if (captureInfo.hasDynamicSelfCapture()) { - DynamicSelfCaptureLoc = innerClosure.getLoc(); + DynamicSelfCaptureLoc = loc; DynamicSelf = captureInfo.getDynamicSelfType(); } + } if (!OpaqueValue) { if (captureInfo.hasOpaqueValueCapture()) @@ -368,13 +366,13 @@ class FindCapturedVars : public ASTWalker { bool walkToDeclPre(Decl *D) override { if (auto *AFD = dyn_cast(D)) { - propagateCaptures(AFD, AFD->getLoc()); + TypeChecker::computeCaptures(AFD); + propagateCaptures(AFD->getCaptureInfo(), AFD->getLoc()); - // Can default parameter initializers capture state? That seems like - // a really bad idea. - for (auto *param : *AFD->getParameters()) - if (auto E = param->getDefaultValue()) - E->walk(*this); + for (auto *P : *AFD->getParameters()) + if (P->getDefaultValue()) + propagateCaptures(P->getDefaultArgumentCaptureInfo(), + P->getLoc()); return false; } @@ -569,7 +567,8 @@ class FindCapturedVars : public ASTWalker { // list computed; we just propagate it, filtering out stuff that they // capture from us. if (auto *SubCE = dyn_cast(E)) { - propagateCaptures(SubCE, SubCE->getStartLoc()); + TypeChecker::computeCaptures(SubCE); + propagateCaptures(SubCE->getCaptureInfo(), SubCE->getLoc()); return { false, E }; } @@ -609,17 +608,36 @@ void TypeChecker::computeCaptures(AnyFunctionRef AFR) { finder.checkType(AFR.getType(), AFR.getLoc()); } - auto captures = finder.getCaptureInfo(); - // A generic function always captures outer generic parameters. + bool isGeneric = false; auto *AFD = AFR.getAbstractFunctionDecl(); - if (AFD) { - if (AFD->getGenericParams()) - captures.setGenericParamCaptures(true); - } + if (AFD) + isGeneric = AFD->isGeneric(); + auto captures = finder.getCaptureInfo(); + if (isGeneric) + captures.setGenericParamCaptures(true); AFR.setCaptureInfo(captures); + // Compute captures for default argument expressions. + if (auto *AFD = AFR.getAbstractFunctionDecl()) { + for (auto *P : *AFD->getParameters()) { + if (auto E = P->getDefaultValue()) { + FindCapturedVars finder(Context, + E->getLoc(), + AFD, + /*isNoEscape=*/false, + /*isObjC=*/false); + E->walk(finder); + + auto captures = finder.getCaptureInfo(); + if (isGeneric) + captures.setGenericParamCaptures(true); + P->setDefaultArgumentCaptureInfo(captures); + } + } + } + // Extensions of generic ObjC functions can't use generic parameters from // their context. if (AFD && finder.getGenericParamCaptureLoc().isValid()) { diff --git a/test/SILGen/capture_order.swift b/test/SILGen/capture_order.swift index 591285115c139..8b772f5d65bef 100644 --- a/test/SILGen/capture_order.swift +++ b/test/SILGen/capture_order.swift @@ -192,10 +192,10 @@ class rdar40600800 { } func innerFunction() { - let closure = { // expected-note {{captured here}} + let closure = { // FIXME: Bogus warning! // expected-warning@-2 {{initialization of immutable value 'closure' was never used; consider replacing with assignment to '_' or removing it}} - callback() + callback() // expected-note {{captured here}} } } } From e1e6f0e7ba89bd7a1e369a291bf419cf250919d5 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 17 Sep 2019 18:11:38 -0400 Subject: [PATCH 076/199] SIL: Refactor type lowering computation of the effective generic signature This also fixes a long-standing bug with default argument expressions capturing generic parameters. --- include/swift/SIL/TypeLowering.h | 18 +- lib/AST/ASTDumper.cpp | 10 +- lib/SIL/TypeLowering.cpp | 230 ++++++++++---------- lib/Sema/TypeCheckCaptures.cpp | 6 - test/SILGen/default_arguments_generic.swift | 13 ++ 5 files changed, 142 insertions(+), 135 deletions(-) diff --git a/include/swift/SIL/TypeLowering.h b/include/swift/SIL/TypeLowering.h index 0e9e35da34add..5c48ff9728dc6 100644 --- a/include/swift/SIL/TypeLowering.h +++ b/include/swift/SIL/TypeLowering.h @@ -844,10 +844,13 @@ class TypeConverter { /// Returns the formal type, lowered AST type, and SILFunctionType /// for a constant reference. const SILConstantInfo &getConstantInfo(SILDeclRef constant); - + + /// Get the generic environment for a constant. + GenericSignature *getConstantGenericSignature(SILDeclRef constant); + /// Get the generic environment for a constant. GenericEnvironment *getConstantGenericEnvironment(SILDeclRef constant); - + /// Returns the SIL type of a constant reference. SILType getConstantType(SILDeclRef constant) { return getConstantInfo(constant).getSILType(); @@ -944,17 +947,6 @@ class TypeConverter { SILType getSubstitutedStorageType(AbstractStorageDecl *value, Type lvalueType); - /// Retrieve the set of archetypes closed over by the given function. - GenericEnvironment *getEffectiveGenericEnvironment(AnyFunctionRef fn, - CaptureInfo captureInfo); - - /// Retrieve the set of generic parameters closed over by the given function. - CanGenericSignature getEffectiveGenericSignature(AnyFunctionRef fn, - CaptureInfo captureInfo); - - /// Retrieve the set of generic parameters closed over by the context. - CanGenericSignature getEffectiveGenericSignature(DeclContext *dc); - /// Push a generic function context. See GenericContextScope for an RAII /// interface to this function. /// diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index c7a67f5c32500..5beb1dfe5ffff 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -988,9 +988,17 @@ namespace { if (P->isAutoClosure()) OS << " autoclosure"; - if (P->getDefaultArgumentKind() != DefaultArgumentKind::None) + if (P->getDefaultArgumentKind() != DefaultArgumentKind::None) { printField("default_arg", getDefaultArgumentKindString(P->getDefaultArgumentKind())); + } + + if (P->getDefaultValue() && + !P->getDefaultArgumentCaptureInfo().isTrivial()) { + OS << " "; + P->getDefaultArgumentCaptureInfo().print( + PrintWithColorRAII(OS, CapturesColor).getOS()); + } if (auto init = P->getDefaultValue()) { OS << " expression=\n"; diff --git a/lib/SIL/TypeLowering.cpp b/lib/SIL/TypeLowering.cpp index ac0aefd8f6d98..87d0e0d30aaab 100644 --- a/lib/SIL/TypeLowering.cpp +++ b/lib/SIL/TypeLowering.cpp @@ -22,6 +22,7 @@ #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" +#include "swift/AST/ParameterList.h" #include "swift/AST/Pattern.h" #include "swift/AST/PropertyWrappers.h" #include "swift/AST/Types.h" @@ -1726,6 +1727,34 @@ getTypeLoweringForExpansion(TypeKey key, return nullptr; } +static GenericSignature * +getEffectiveGenericSignature(DeclContext *dc) { + if (auto sig = dc->getGenericSignatureOfContext()) { + if (sig->areAllParamsConcrete()) + return nullptr; + return sig; + } + + return nullptr; +} + +static GenericSignature * +getEffectiveGenericSignature(AnyFunctionRef fn, + CaptureInfo captureInfo) { + auto dc = fn.getAsDeclContext(); + + if (dc->getParent()->isLocalContext() && + !captureInfo.hasGenericParamCaptures()) + return nullptr; + + return getEffectiveGenericSignature(dc); +} + +static CanGenericSignature +getCanonicalSignatureOrNull(GenericSignature *sig) { + return sig ? sig->getCanonicalSignature() : nullptr; +} + /// Get the type of a global variable accessor function, () -> RawPointer. static CanAnyFunctionType getGlobalAccessorType(CanType varType) { ASTContext &C = varType->getASTContext(); @@ -1735,16 +1764,17 @@ static CanAnyFunctionType getGlobalAccessorType(CanType varType) { /// Get the type of a default argument generator, () -> T. static CanAnyFunctionType getDefaultArgGeneratorInterfaceType( TypeConverter &TC, - ValueDecl *VD, - DeclContext *DC, - unsigned DefaultArgIndex) { - auto resultTy = getParameterAt(VD, DefaultArgIndex)->getInterfaceType(); + SILDeclRef c) { + auto *vd = c.getDecl(); + auto resultTy = getParameterAt(vd, + c.defaultArgIndex)->getInterfaceType(); assert(resultTy && "Didn't find default argument?"); // The result type might be written in terms of type parameters // that have been made fully concrete. CanType canResultTy = resultTy->getCanonicalType( - DC->getGenericSignatureOfContext()); + vd->getInnermostDeclContext() + ->getGenericSignatureOfContext()); // Remove @noescape from function return types. A @noescape // function return type is a contradiction. @@ -1755,19 +1785,13 @@ static CanAnyFunctionType getDefaultArgGeneratorInterfaceType( } // Get the generic signature from the surrounding context. - CanGenericSignature sig; - if (auto *afd = dyn_cast(VD)) { - auto funcInfo = TC.getConstantInfo(SILDeclRef(VD)); - sig = funcInfo.FormalType.getOptGenericSignature(); - } else { - sig = TC.getEffectiveGenericSignature(DC); - } - return CanAnyFunctionType::get(sig, {}, canResultTy); + auto sig = TC.getConstantGenericSignature(c); + return CanAnyFunctionType::get(getCanonicalSignatureOrNull(sig), + {}, canResultTy); } /// Get the type of a stored property initializer, () -> T. static CanAnyFunctionType getStoredPropertyInitializerInterfaceType( - TypeConverter &TC, VarDecl *VD) { auto *DC = VD->getDeclContext(); CanType resultTy = @@ -1782,14 +1806,14 @@ static CanAnyFunctionType getStoredPropertyInitializerInterfaceType( resultTy = originalProperty->getValueInterfaceType()->getCanonicalType(); } - auto sig = TC.getEffectiveGenericSignature(DC); + auto sig = getEffectiveGenericSignature(DC); - return CanAnyFunctionType::get(sig, {}, resultTy); + return CanAnyFunctionType::get(getCanonicalSignatureOrNull(sig), + {}, resultTy); } /// Get the type of a destructor function. -static CanAnyFunctionType getDestructorInterfaceType(TypeConverter &TC, - DestructorDecl *dd, +static CanAnyFunctionType getDestructorInterfaceType(DestructorDecl *dd, bool isDeallocating, bool isForeign) { auto classType = dd->getDeclContext()->getDeclaredInterfaceType() @@ -1807,29 +1831,29 @@ static CanAnyFunctionType getDestructorInterfaceType(TypeConverter &TC, extInfo = extInfo .withSILRepresentation(SILFunctionTypeRepresentation::Method); - auto &C = TC.Context; + auto &C = dd->getASTContext(); CanType resultTy = (isDeallocating ? TupleType::getEmpty(C) : C.TheNativeObjectType); CanType methodTy = CanFunctionType::get({}, resultTy); - auto sig = TC.getEffectiveGenericSignature(dd); + auto sig = getEffectiveGenericSignature(dd); FunctionType::Param args[] = {FunctionType::Param(classType)}; - return CanAnyFunctionType::get(sig, llvm::makeArrayRef(args), + return CanAnyFunctionType::get(getCanonicalSignatureOrNull(sig), + llvm::makeArrayRef(args), methodTy, extInfo); } /// Retrieve the type of the ivar initializer or destroyer method for /// a class. -static CanAnyFunctionType getIVarInitDestroyerInterfaceType(TypeConverter &TC, - ClassDecl *cd, +static CanAnyFunctionType getIVarInitDestroyerInterfaceType(ClassDecl *cd, bool isObjC, bool isDestroyer) { auto classType = cd->getDeclaredInterfaceType() ->getCanonicalType(cd->getGenericSignatureOfContext()); auto resultType = (isDestroyer - ? TupleType::getEmpty(TC.Context) + ? TupleType::getEmpty(cd->getASTContext()) : classType); auto extInfo = AnyFunctionType::ExtInfo(FunctionType::Representation::Thin, /*throws*/ false); @@ -1838,46 +1862,13 @@ static CanAnyFunctionType getIVarInitDestroyerInterfaceType(TypeConverter &TC, : SILFunctionTypeRepresentation::Method); resultType = CanFunctionType::get({}, resultType, extInfo); - auto sig = TC.getEffectiveGenericSignature(cd); + auto sig = getEffectiveGenericSignature(cd); FunctionType::Param args[] = {FunctionType::Param(classType)}; - return CanAnyFunctionType::get(sig, llvm::makeArrayRef(args), + return CanAnyFunctionType::get(getCanonicalSignatureOrNull(sig), + llvm::makeArrayRef(args), resultType, extInfo); } -GenericEnvironment * -TypeConverter::getEffectiveGenericEnvironment(AnyFunctionRef fn, - CaptureInfo captureInfo) { - auto dc = fn.getAsDeclContext(); - - if (getEffectiveGenericSignature(fn, captureInfo)) - return dc->getGenericEnvironmentOfContext(); - - return nullptr; -} - -CanGenericSignature -TypeConverter::getEffectiveGenericSignature(DeclContext *dc) { - if (auto sig = dc->getGenericSignatureOfContext()) { - if (sig->areAllParamsConcrete()) - return nullptr; - return sig->getCanonicalSignature(); - } - - return nullptr; -} - -CanGenericSignature -TypeConverter::getEffectiveGenericSignature(AnyFunctionRef fn, - CaptureInfo captureInfo) { - auto dc = fn.getAsDeclContext(); - - if (dc->getParent()->isLocalContext() && - !captureInfo.hasGenericParamCaptures()) - return nullptr; - - return getEffectiveGenericSignature(dc); -} - CanAnyFunctionType TypeConverter::getFunctionInterfaceTypeWithCaptures(CanAnyFunctionType funcType, AnyFunctionRef theClosure) { @@ -1886,14 +1877,15 @@ TypeConverter::getFunctionInterfaceTypeWithCaptures(CanAnyFunctionType funcType, auto captureInfo = getLoweredLocalCaptures(theClosure); // Capture generic parameters from the enclosing context if necessary. - CanGenericSignature genericSig = getEffectiveGenericSignature(theClosure, - captureInfo); + auto *genericSig = getEffectiveGenericSignature(theClosure, captureInfo); auto innerExtInfo = AnyFunctionType::ExtInfo(FunctionType::Representation::Thin, funcType->throws()); - return CanAnyFunctionType::get(genericSig, funcType.getParams(), - funcType.getResult(), innerExtInfo); + return CanAnyFunctionType::get( + getCanonicalSignatureOrNull(genericSig), + funcType.getParams(), funcType.getResult(), + innerExtInfo); } CanAnyFunctionType TypeConverter::makeConstantInterfaceType(SILDeclRef c) { @@ -1924,7 +1916,7 @@ CanAnyFunctionType TypeConverter::makeConstantInterfaceType(SILDeclRef c) { auto funcTy = cast( vd->getInterfaceType()->getCanonicalType()); auto sig = getEffectiveGenericSignature(vd->getDeclContext()); - return CanAnyFunctionType::get(sig, + return CanAnyFunctionType::get(getCanonicalSignatureOrNull(sig), funcTy->getParams(), funcTy.getResult(), funcTy->getExtInfo()); @@ -1946,8 +1938,7 @@ CanAnyFunctionType TypeConverter::makeConstantInterfaceType(SILDeclRef c) { case SILDeclRef::Kind::Destroyer: case SILDeclRef::Kind::Deallocator: - return getDestructorInterfaceType(*this, - cast(vd), + return getDestructorInterfaceType(cast(vd), c.kind == SILDeclRef::Kind::Deallocator, c.isForeign); @@ -1958,28 +1949,22 @@ CanAnyFunctionType TypeConverter::makeConstantInterfaceType(SILDeclRef c) { return getGlobalAccessorType(var->getInterfaceType()->getCanonicalType()); } case SILDeclRef::Kind::DefaultArgGenerator: - return getDefaultArgGeneratorInterfaceType(*this, vd, - vd->getInnermostDeclContext(), - c.defaultArgIndex); + return getDefaultArgGeneratorInterfaceType(*this, c); case SILDeclRef::Kind::StoredPropertyInitializer: - return getStoredPropertyInitializerInterfaceType(*this, - cast(vd)); + return getStoredPropertyInitializerInterfaceType(cast(vd)); case SILDeclRef::Kind::IVarInitializer: - return getIVarInitDestroyerInterfaceType(*this, - cast(vd), + return getIVarInitDestroyerInterfaceType(cast(vd), c.isForeign, false); case SILDeclRef::Kind::IVarDestroyer: - return getIVarInitDestroyerInterfaceType(*this, - cast(vd), + return getIVarInitDestroyerInterfaceType(cast(vd), c.isForeign, true); } llvm_unreachable("Unhandled SILDeclRefKind in switch."); } -/// Get the generic environment for an entity. -GenericEnvironment * -TypeConverter::getConstantGenericEnvironment(SILDeclRef c) { +GenericSignature * +TypeConverter::getConstantGenericSignature(SILDeclRef c) { auto *vd = c.loc.dyn_cast(); /// Get the function generic params, including outer params. @@ -1987,17 +1972,15 @@ TypeConverter::getConstantGenericEnvironment(SILDeclRef c) { case SILDeclRef::Kind::Func: { if (auto *ACE = c.getAbstractClosureExpr()) { auto captureInfo = getLoweredLocalCaptures(ACE); - - return getEffectiveGenericEnvironment(ACE, captureInfo); + return getEffectiveGenericSignature(ACE, captureInfo); } FuncDecl *func = cast(vd); auto captureInfo = getLoweredLocalCaptures(func); - - return getEffectiveGenericEnvironment(func, captureInfo); + return getEffectiveGenericSignature(func, captureInfo); } case SILDeclRef::Kind::EnumElement: { auto eltDecl = cast(vd); - return eltDecl->getDeclContext()->getGenericEnvironmentOfContext(); + return getEffectiveGenericSignature(eltDecl->getDeclContext()); } case SILDeclRef::Kind::Allocator: case SILDeclRef::Kind::Initializer: @@ -2005,27 +1988,36 @@ TypeConverter::getConstantGenericEnvironment(SILDeclRef c) { case SILDeclRef::Kind::Deallocator: { auto *afd = cast(vd); auto captureInfo = getLoweredLocalCaptures(afd); - return getEffectiveGenericEnvironment(afd, captureInfo); + return getEffectiveGenericSignature(afd, captureInfo); } case SILDeclRef::Kind::GlobalAccessor: - return vd->getDeclContext()->getGenericEnvironmentOfContext(); + return getEffectiveGenericSignature(vd->getDeclContext()); case SILDeclRef::Kind::IVarInitializer: case SILDeclRef::Kind::IVarDestroyer: - return cast(vd)->getGenericEnvironmentOfContext(); + return getEffectiveGenericSignature(cast(vd)); case SILDeclRef::Kind::DefaultArgGenerator: // Use the generic environment of the original function. - if (auto *afd = dyn_cast(c.getDecl())) - return getConstantGenericEnvironment(SILDeclRef(c.getDecl())); - return c.getDecl()->getInnermostDeclContext() - ->getGenericEnvironmentOfContext(); + if (auto *afd = dyn_cast(c.getDecl())) { + auto captureInfo = getLoweredLocalCaptures(afd); + return getEffectiveGenericSignature(afd, captureInfo); + } + return getEffectiveGenericSignature( + c.getDecl()->getInnermostDeclContext()); case SILDeclRef::Kind::StoredPropertyInitializer: // Use the generic environment of the containing type. - return c.getDecl()->getDeclContext()->getGenericEnvironmentOfContext(); + return getEffectiveGenericSignature(c.getDecl()->getDeclContext()); } llvm_unreachable("Unhandled SILDeclRefKind in switch."); } +GenericEnvironment * +TypeConverter::getConstantGenericEnvironment(SILDeclRef c) { + if (auto *sig = getConstantGenericSignature(c)) + return sig->getGenericEnvironment(); + return nullptr; +} + SILType TypeConverter::getSubstitutedStorageType(AbstractStorageDecl *value, Type lvalueType) { // The l-value type is the result of applying substitutions to @@ -2121,16 +2113,6 @@ TypeConverter::hasLoweredLocalCaptures(AnyFunctionRef fn) { CaptureInfo TypeConverter::getLoweredLocalCaptures(AnyFunctionRef fn) { - // First, bail out if there are no local captures at all. - if (!fn.getCaptureInfo().hasLocalCaptures() && - !fn.getCaptureInfo().hasOpaqueValueCapture() && - !fn.getCaptureInfo().hasDynamicSelfCapture()) { - CaptureInfo info; - info.setGenericParamCaptures( - fn.getCaptureInfo().hasGenericParamCaptures()); - return info; - }; - // See if we've cached the lowered capture list for this function. auto found = LoweredCaptures.find(fn); if (found != LoweredCaptures.end()) @@ -2148,20 +2130,19 @@ TypeConverter::getLoweredLocalCaptures(AnyFunctionRef fn) { DynamicSelfType *capturesDynamicSelf = nullptr; OpaqueValueExpr *capturesOpaqueValue = nullptr; - std::function collectFunctionCaptures - = [&](AnyFunctionRef curFn) { - if (!visitedFunctions.insert(curFn).second) - return; - - if (curFn.getCaptureInfo().hasGenericParamCaptures()) + std::function collectCaptures; + std::function collectFunctionCaptures; + + collectCaptures = [&](const CaptureInfo &captureInfo) { + if (captureInfo.hasGenericParamCaptures()) capturesGenericParams = true; - if (curFn.getCaptureInfo().hasDynamicSelfCapture()) - capturesDynamicSelf = curFn.getCaptureInfo().getDynamicSelfType(); - if (curFn.getCaptureInfo().hasOpaqueValueCapture()) - capturesOpaqueValue = curFn.getCaptureInfo().getOpaqueValue(); + if (captureInfo.hasDynamicSelfCapture()) + capturesDynamicSelf = captureInfo.getDynamicSelfType(); + if (captureInfo.hasOpaqueValueCapture()) + capturesOpaqueValue = captureInfo.getOpaqueValue(); SmallVector localCaptures; - curFn.getCaptureInfo().getLocalCaptures(localCaptures); + captureInfo.getLocalCaptures(localCaptures); for (auto capture : localCaptures) { // If the capture is of another local function, grab its transitive // captures instead. @@ -2274,6 +2255,23 @@ TypeConverter::getLoweredLocalCaptures(AnyFunctionRef fn) { } } }; + + collectFunctionCaptures = [&](AnyFunctionRef curFn) { + if (!visitedFunctions.insert(curFn).second) + return; + + collectCaptures(curFn.getCaptureInfo()); + + // Also visit default argument captures. + // FIXME: This should be more fine-grained -- we should only need the + // captures for default arguments that are actually referenced. + if (auto *AFD = curFn.getAbstractFunctionDecl()) { + for (auto *P : *AFD->getParameters()) { + if (P->getDefaultValue()) + collectCaptures(P->getDefaultArgumentCaptureInfo()); + } + } + }; collectFunctionCaptures(fn); SmallVector resultingCaptures; @@ -2519,7 +2517,8 @@ TypeConverter::getInterfaceBoxTypeForCapture(ValueDecl *captured, CanType loweredInterfaceType, bool isMutable) { auto &C = M.getASTContext(); - auto signature = getEffectiveGenericSignature(captured->getDeclContext()); + auto signature = getCanonicalSignatureOrNull( + getEffectiveGenericSignature(captured->getDeclContext())); // If the type is not dependent at all, we can form a concrete box layout. // We don't need to capture the generic environment. @@ -2606,7 +2605,8 @@ CanSILBoxType TypeConverter::getBoxTypeForEnumElement(SILType enumType, if (!elt->hasInterfaceType()) Context.getLazyResolver()->resolveDeclSignature(elt); - auto boxSignature = getEffectiveGenericSignature(enumDecl); + auto boxSignature = getCanonicalSignatureOrNull( + getEffectiveGenericSignature(enumDecl)); if (boxSignature == CanGenericSignature()) { auto eltIntfTy = elt->getArgumentInterfaceType(); diff --git a/lib/Sema/TypeCheckCaptures.cpp b/lib/Sema/TypeCheckCaptures.cpp index 2ea6e7aad875f..98547c82da531 100644 --- a/lib/Sema/TypeCheckCaptures.cpp +++ b/lib/Sema/TypeCheckCaptures.cpp @@ -368,12 +368,6 @@ class FindCapturedVars : public ASTWalker { if (auto *AFD = dyn_cast(D)) { TypeChecker::computeCaptures(AFD); propagateCaptures(AFD->getCaptureInfo(), AFD->getLoc()); - - for (auto *P : *AFD->getParameters()) - if (P->getDefaultValue()) - propagateCaptures(P->getDefaultArgumentCaptureInfo(), - P->getLoc()); - return false; } diff --git a/test/SILGen/default_arguments_generic.swift b/test/SILGen/default_arguments_generic.swift index d0562d3c0bff2..7027ce86c2fad 100644 --- a/test/SILGen/default_arguments_generic.swift +++ b/test/SILGen/default_arguments_generic.swift @@ -71,3 +71,16 @@ func outer(t: T) { // CHECK: [[ARG:%.*]] = apply [[ARG_GENERATOR]]() : $@convention(thin) <τ_0_0> () -> Int _ = inner2() } + +protocol StaticIntValue { + static var intValue: Int { get } +} + +func f(_: T) { + // CHECK-LABEL: sil private [ossa] @$s25default_arguments_generic1fyyxAA14StaticIntValueRzlF5innerL_1xySi_tAaCRzlFfA_ : $@convention(thin) () -> Int + // CHECK-LABEL: sil private [ossa] @$s25default_arguments_generic1fyyxAA14StaticIntValueRzlF5innerL_1xySi_tAaCRzlF : $@convention(thin) (Int) -> () + func inner(x: Int = T.intValue) {} + + // CHECK-LABEL: sil private [ossa] @$s25default_arguments_generic1fyyxAA14StaticIntValueRzlF5otherL_yyAaCRzlF : $@convention(thin) () -> () + func other() { inner() } +} \ No newline at end of file From d3a4f3ded088448a57407462dc34661a8aa1b2b4 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 17 Sep 2019 18:20:12 -0400 Subject: [PATCH 077/199] Sema: Diagnose captures of dynamic 'Self' type from default argument expressions We could actually allow this for local functions, but it's not worth implementing that until the more general ability of local function default arguments to capture values is implemented. Fixes . --- include/swift/AST/DiagnosticsSema.def | 2 ++ lib/Sema/TypeCheckCaptures.cpp | 5 +++++ test/decl/func/dynamic_self.swift | 8 ++++++++ 3 files changed, 15 insertions(+) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index fc41021cc9745..f3644b571c839 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -2655,6 +2655,8 @@ ERROR(dynamic_self_invalid_method,none, "covariant 'Self' can only appear at the top level of method result type", ()) ERROR(dynamic_self_stored_property_init,none, "covariant 'Self' type cannot be referenced from a stored property initializer", ()) +ERROR(dynamic_self_default_arg,none, + "covariant 'Self' type cannot be referenced from a default argument expression", ()) //------------------------------------------------------------------------------ // MARK: Type Check Attributes diff --git a/lib/Sema/TypeCheckCaptures.cpp b/lib/Sema/TypeCheckCaptures.cpp index 98547c82da531..f91a0e5dadf48 100644 --- a/lib/Sema/TypeCheckCaptures.cpp +++ b/lib/Sema/TypeCheckCaptures.cpp @@ -624,6 +624,11 @@ void TypeChecker::computeCaptures(AnyFunctionRef AFR) { /*isObjC=*/false); E->walk(finder); + if (finder.getDynamicSelfCaptureLoc().isValid()) { + Context.Diags.diagnose(finder.getDynamicSelfCaptureLoc(), + diag::dynamic_self_default_arg); + } + auto captures = finder.getCaptureInfo(); if (isGeneric) captures.setGenericParamCaptures(true); diff --git a/test/decl/func/dynamic_self.swift b/test/decl/func/dynamic_self.swift index ca499e0571cec..1c748f1b1fd9e 100644 --- a/test/decl/func/dynamic_self.swift +++ b/test/decl/func/dynamic_self.swift @@ -437,3 +437,11 @@ class Iterable : Sequence { return DummyIterator() } } + +// Default arguments of methods cannot capture 'Self' or 'self' +class MathClass { + func invalidDefaultArg(s: Int = Self.intMethod()) {} + // expected-error@-1 {{covariant 'Self' type cannot be referenced from a default argument expression}} + + static func intMethod() -> Int { return 0 } +} From b8642b0965476b9707a7089c2b46fc2aec132888 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 18 Sep 2019 00:48:52 -0400 Subject: [PATCH 078/199] SILGen: Fix crash when immediately-applied closure transitively captures generic parameters --- lib/SILGen/SILGenApply.cpp | 7 ++++--- test/SILGen/default_arguments_generic.swift | 10 +++++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index f3930475d215f..c6a6756c0b7ee 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -1163,15 +1163,16 @@ class SILGenApply : public Lowering::ExprVisitor { // really producing a closure object. SILDeclRef constant(e); + auto captureInfo = SGF.SGM.M.Types.getLoweredLocalCaptures(e); + SubstitutionMap subs; - if (e->getCaptureInfo().hasGenericParamCaptures()) + if (captureInfo.hasGenericParamCaptures()) subs = SGF.getForwardingSubstitutionMap(); setCallee(Callee::forDirect(SGF, constant, subs, e)); // If the closure requires captures, emit them. - bool hasCaptures = SGF.SGM.M.Types.hasLoweredLocalCaptures(e); - if (hasCaptures) { + if (!captureInfo.getCaptures().empty()) { SmallVector captures; SGF.emitCaptures(e, e, CaptureEmission::ImmediateApplication, captures); diff --git a/test/SILGen/default_arguments_generic.swift b/test/SILGen/default_arguments_generic.swift index 7027ce86c2fad..9c01a9d554ebd 100644 --- a/test/SILGen/default_arguments_generic.swift +++ b/test/SILGen/default_arguments_generic.swift @@ -83,4 +83,12 @@ func f(_: T) { // CHECK-LABEL: sil private [ossa] @$s25default_arguments_generic1fyyxAA14StaticIntValueRzlF5otherL_yyAaCRzlF : $@convention(thin) () -> () func other() { inner() } -} \ No newline at end of file +} + +func g(_: T) { + { inner() }() + + func inner() { + _ = T.self + } +} From 533d41d0db7efc4d3b1ee28cbec121b8fc22ff47 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 18 Sep 2019 00:49:35 -0400 Subject: [PATCH 079/199] SIL: Compute lowered local captures of SILDeclRefs and not AnyFunctionRefs Unfortuantely this commit is bigger than I would like but I couldn't think of any reasonable ways to split it up. The general idea here is that capture computation is now done for a SILDeclRef and not an AnyFunctionRef. This allows SIL to represent the captures of a default argument generator. --- include/swift/SIL/TypeLowering.h | 15 +- lib/SIL/SILFunctionType.cpp | 23 +-- lib/SIL/TypeLowering.cpp | 159 +++++++++++--------- lib/SILGen/SILGenApply.cpp | 16 +- lib/SILGen/SILGenConstructor.cpp | 5 +- lib/SILGen/SILGenExpr.cpp | 3 +- lib/SILGen/SILGenFunction.cpp | 50 ++++-- lib/SILGen/SILGenFunction.h | 10 +- lib/SILGen/SILGenProlog.cpp | 39 ++--- lib/SILGen/SILGenThunk.cpp | 2 +- test/SILGen/default_arguments_generic.swift | 4 +- 11 files changed, 175 insertions(+), 151 deletions(-) diff --git a/include/swift/SIL/TypeLowering.h b/include/swift/SIL/TypeLowering.h index 5c48ff9728dc6..6361b8f3bba95 100644 --- a/include/swift/SIL/TypeLowering.h +++ b/include/swift/SIL/TypeLowering.h @@ -689,7 +689,7 @@ class TypeConverter { llvm::DenseMap ConstantOverrideTypes; - llvm::DenseMap LoweredCaptures; + llvm::DenseMap LoweredCaptures; /// Cache of loadable SILType to number of (estimated) fields /// @@ -896,11 +896,6 @@ class TypeConverter { SILType getEmptyTupleType() { return SILType::getPrimitiveObjectType(TupleType::getEmpty(Context)); } - - /// Get a function type curried with its capture context. - CanAnyFunctionType getFunctionInterfaceTypeWithCaptures( - CanAnyFunctionType funcType, - AnyFunctionRef closure); /// Describes what we're trying to compute a bridged type for. /// @@ -972,10 +967,10 @@ class TypeConverter { CanType get##BridgedType##Type(); #include "swift/SIL/BridgedTypes.def" - /// Get the capture list from a closure, with transitive function captures - /// flattened. - CaptureInfo getLoweredLocalCaptures(AnyFunctionRef fn); - bool hasLoweredLocalCaptures(AnyFunctionRef fn); + /// Get the capture list for a function or default argument, with transitive + /// function captures flattened. + CaptureInfo getLoweredLocalCaptures(SILDeclRef fn); + bool hasLoweredLocalCaptures(SILDeclRef fn); enum class ABIDifference : uint8_t { // No ABI differences, function can be trivially bitcast to result type. diff --git a/lib/SIL/SILFunctionType.cpp b/lib/SIL/SILFunctionType.cpp index 0566670b7fd9b..5757e24f5ef94 100644 --- a/lib/SIL/SILFunctionType.cpp +++ b/lib/SIL/SILFunctionType.cpp @@ -715,7 +715,7 @@ static std::pair updateResultTypeForForeignError( /// If we ever add that ability, it will be a different capture list /// from the function to which the argument is attached. static void -lowerCaptureContextParameters(TypeConverter &TC, AnyFunctionRef function, +lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function, CanGenericSignature genericSig, ResilienceExpansion expansion, SmallVectorImpl &inputs) { @@ -725,8 +725,7 @@ lowerCaptureContextParameters(TypeConverter &TC, AnyFunctionRef function, // canonicalize references to the generic parameters that may appear in // non-canonical types in that context. We need the original generic // signature from the AST for that. - auto origGenericSig = function.getGenericSignature(); - + auto origGenericSig = function.getAnyFunctionRef()->getGenericSignature(); auto loweredCaptures = TC.getLoweredLocalCaptures(function); for (auto capture : loweredCaptures.getCaptures()) { @@ -999,18 +998,12 @@ static CanSILFunctionType getSILFunctionType( yields, coroutineKind); // Lower the capture context parameters, if any. - // - // *NOTE* Currently default arg generators can not capture anything. - // If we ever add that ability, it will be a different capture list - // from the function to which the argument is attached. - if (constant && !constant->isDefaultArgGenerator()) { - if (auto function = constant->getAnyFunctionRef()) { - auto expansion = ResilienceExpansion::Maximal; - if (constant->isSerialized()) - expansion = ResilienceExpansion::Minimal; - lowerCaptureContextParameters(TC, *function, genericSig, expansion, - inputs); - } + if (constant && constant->getAnyFunctionRef()) { + auto expansion = ResilienceExpansion::Maximal; + if (constant->isSerialized()) + expansion = ResilienceExpansion::Minimal; + lowerCaptureContextParameters(TC, *constant, genericSig, expansion, + inputs); } auto calleeConvention = ParameterConvention::Direct_Unowned; diff --git a/lib/SIL/TypeLowering.cpp b/lib/SIL/TypeLowering.cpp index 87d0e0d30aaab..cc79428694489 100644 --- a/lib/SIL/TypeLowering.cpp +++ b/lib/SIL/TypeLowering.cpp @@ -1728,31 +1728,27 @@ getTypeLoweringForExpansion(TypeKey key, } static GenericSignature * -getEffectiveGenericSignature(DeclContext *dc) { - if (auto sig = dc->getGenericSignatureOfContext()) { - if (sig->areAllParamsConcrete()) - return nullptr; - return sig; - } +getEffectiveGenericSignature(DeclContext *dc, + CaptureInfo captureInfo) { + if (dc->getParent()->isLocalContext() && + !captureInfo.hasGenericParamCaptures()) + return nullptr; - return nullptr; + return dc->getGenericSignatureOfContext(); } static GenericSignature * getEffectiveGenericSignature(AnyFunctionRef fn, CaptureInfo captureInfo) { - auto dc = fn.getAsDeclContext(); - - if (dc->getParent()->isLocalContext() && - !captureInfo.hasGenericParamCaptures()) - return nullptr; - - return getEffectiveGenericSignature(dc); + return getEffectiveGenericSignature(fn.getAsDeclContext(), captureInfo); } static CanGenericSignature getCanonicalSignatureOrNull(GenericSignature *sig) { - return sig ? sig->getCanonicalSignature() : nullptr; + if (!sig || sig->areAllParamsConcrete()) + return nullptr; + + return sig->getCanonicalSignature(); } /// Get the type of a global variable accessor function, () -> RawPointer. @@ -1763,7 +1759,6 @@ static CanAnyFunctionType getGlobalAccessorType(CanType varType) { /// Get the type of a default argument generator, () -> T. static CanAnyFunctionType getDefaultArgGeneratorInterfaceType( - TypeConverter &TC, SILDeclRef c) { auto *vd = c.getDecl(); auto resultTy = getParameterAt(vd, @@ -1785,7 +1780,15 @@ static CanAnyFunctionType getDefaultArgGeneratorInterfaceType( } // Get the generic signature from the surrounding context. - auto sig = TC.getConstantGenericSignature(c); + auto *sig = vd->getInnermostDeclContext()->getGenericSignatureOfContext(); + if (auto *afd = dyn_cast(vd)) { + auto *param = getParameterAt(afd, c.defaultArgIndex); + if (param->getDefaultValue()) { + auto &captureInfo = param->getDefaultArgumentCaptureInfo(); + sig = getEffectiveGenericSignature(afd, captureInfo); + } + } + return CanAnyFunctionType::get(getCanonicalSignatureOrNull(sig), {}, canResultTy); } @@ -1806,7 +1809,7 @@ static CanAnyFunctionType getStoredPropertyInitializerInterfaceType( resultTy = originalProperty->getValueInterfaceType()->getCanonicalType(); } - auto sig = getEffectiveGenericSignature(DC); + auto sig = DC->getGenericSignatureOfContext(); return CanAnyFunctionType::get(getCanonicalSignatureOrNull(sig), {}, resultTy); @@ -1837,7 +1840,7 @@ static CanAnyFunctionType getDestructorInterfaceType(DestructorDecl *dd, : C.TheNativeObjectType); CanType methodTy = CanFunctionType::get({}, resultTy); - auto sig = getEffectiveGenericSignature(dd); + auto sig = dd->getGenericSignatureOfContext(); FunctionType::Param args[] = {FunctionType::Param(classType)}; return CanAnyFunctionType::get(getCanonicalSignatureOrNull(sig), llvm::makeArrayRef(args), @@ -1862,22 +1865,24 @@ static CanAnyFunctionType getIVarInitDestroyerInterfaceType(ClassDecl *cd, : SILFunctionTypeRepresentation::Method); resultType = CanFunctionType::get({}, resultType, extInfo); - auto sig = getEffectiveGenericSignature(cd); + auto sig = cd->getGenericSignature(); FunctionType::Param args[] = {FunctionType::Param(classType)}; return CanAnyFunctionType::get(getCanonicalSignatureOrNull(sig), llvm::makeArrayRef(args), resultType, extInfo); } -CanAnyFunctionType -TypeConverter::getFunctionInterfaceTypeWithCaptures(CanAnyFunctionType funcType, - AnyFunctionRef theClosure) { +static CanAnyFunctionType +getFunctionInterfaceTypeWithCaptures(TypeConverter &TC, + CanAnyFunctionType funcType, + SILDeclRef constant) { // Get transitive closure of value captured by this function, and any // captured functions. - auto captureInfo = getLoweredLocalCaptures(theClosure); + auto captureInfo = TC.getLoweredLocalCaptures(constant); // Capture generic parameters from the enclosing context if necessary. - auto *genericSig = getEffectiveGenericSignature(theClosure, captureInfo); + auto closure = *constant.getAnyFunctionRef(); + auto *genericSig = getEffectiveGenericSignature(closure, captureInfo); auto innerExtInfo = AnyFunctionType::ExtInfo(FunctionType::Representation::Thin, funcType->throws()); @@ -1897,25 +1902,22 @@ CanAnyFunctionType TypeConverter::makeConstantInterfaceType(SILDeclRef c) { switch (c.kind) { case SILDeclRef::Kind::Func: { + CanAnyFunctionType funcTy; if (auto *ACE = c.loc.dyn_cast()) { // FIXME: Closures could have an interface type computed by Sema. - auto funcTy = cast(ACE->getType()->getCanonicalType()); funcTy = cast( - funcTy->mapTypeOutOfContext() - ->getCanonicalType()); - return getFunctionInterfaceTypeWithCaptures(funcTy, ACE); + ACE->getType()->mapTypeOutOfContext()->getCanonicalType()); + } else { + funcTy = cast( + vd->getInterfaceType()->getCanonicalType()); } - - FuncDecl *func = cast(vd); - auto funcTy = cast( - func->getInterfaceType()->getCanonicalType()); - return getFunctionInterfaceTypeWithCaptures(funcTy, func); + return getFunctionInterfaceTypeWithCaptures(*this, funcTy, c); } case SILDeclRef::Kind::EnumElement: { auto funcTy = cast( - vd->getInterfaceType()->getCanonicalType()); - auto sig = getEffectiveGenericSignature(vd->getDeclContext()); + vd->getInterfaceType()->getCanonicalType()); + auto sig = vd->getDeclContext()->getGenericSignatureOfContext(); return CanAnyFunctionType::get(getCanonicalSignatureOrNull(sig), funcTy->getParams(), funcTy.getResult(), @@ -1926,14 +1928,14 @@ CanAnyFunctionType TypeConverter::makeConstantInterfaceType(SILDeclRef c) { auto *cd = cast(vd); auto funcTy = cast( cd->getInterfaceType()->getCanonicalType()); - return getFunctionInterfaceTypeWithCaptures(funcTy, cd); + return getFunctionInterfaceTypeWithCaptures(*this, funcTy, c); } case SILDeclRef::Kind::Initializer: { auto *cd = cast(vd); auto funcTy = cast( cd->getInitializerInterfaceType()->getCanonicalType()); - return getFunctionInterfaceTypeWithCaptures(funcTy, cd); + return getFunctionInterfaceTypeWithCaptures(*this, funcTy, c); } case SILDeclRef::Kind::Destroyer: @@ -1949,7 +1951,7 @@ CanAnyFunctionType TypeConverter::makeConstantInterfaceType(SILDeclRef c) { return getGlobalAccessorType(var->getInterfaceType()->getCanonicalType()); } case SILDeclRef::Kind::DefaultArgGenerator: - return getDefaultArgGeneratorInterfaceType(*this, c); + return getDefaultArgGeneratorInterfaceType(c); case SILDeclRef::Kind::StoredPropertyInitializer: return getStoredPropertyInitializerInterfaceType(cast(vd)); case SILDeclRef::Kind::IVarInitializer: @@ -1969,43 +1971,28 @@ TypeConverter::getConstantGenericSignature(SILDeclRef c) { /// Get the function generic params, including outer params. switch (c.kind) { - case SILDeclRef::Kind::Func: { - if (auto *ACE = c.getAbstractClosureExpr()) { - auto captureInfo = getLoweredLocalCaptures(ACE); - return getEffectiveGenericSignature(ACE, captureInfo); - } - FuncDecl *func = cast(vd); - auto captureInfo = getLoweredLocalCaptures(func); - return getEffectiveGenericSignature(func, captureInfo); - } - case SILDeclRef::Kind::EnumElement: { - auto eltDecl = cast(vd); - return getEffectiveGenericSignature(eltDecl->getDeclContext()); - } + case SILDeclRef::Kind::Func: case SILDeclRef::Kind::Allocator: case SILDeclRef::Kind::Initializer: case SILDeclRef::Kind::Destroyer: case SILDeclRef::Kind::Deallocator: { - auto *afd = cast(vd); - auto captureInfo = getLoweredLocalCaptures(afd); - return getEffectiveGenericSignature(afd, captureInfo); + auto captureInfo = getLoweredLocalCaptures(c); + return getEffectiveGenericSignature( + *c.getAnyFunctionRef(), captureInfo); } - case SILDeclRef::Kind::GlobalAccessor: - return getEffectiveGenericSignature(vd->getDeclContext()); case SILDeclRef::Kind::IVarInitializer: case SILDeclRef::Kind::IVarDestroyer: - return getEffectiveGenericSignature(cast(vd)); - case SILDeclRef::Kind::DefaultArgGenerator: + return cast(vd)->getGenericSignature(); + case SILDeclRef::Kind::DefaultArgGenerator: { // Use the generic environment of the original function. - if (auto *afd = dyn_cast(c.getDecl())) { - auto captureInfo = getLoweredLocalCaptures(afd); - return getEffectiveGenericSignature(afd, captureInfo); - } + auto captureInfo = getLoweredLocalCaptures(c); return getEffectiveGenericSignature( - c.getDecl()->getInnermostDeclContext()); + vd->getInnermostDeclContext(), captureInfo); + } + case SILDeclRef::Kind::EnumElement: + case SILDeclRef::Kind::GlobalAccessor: case SILDeclRef::Kind::StoredPropertyInitializer: - // Use the generic environment of the containing type. - return getEffectiveGenericSignature(c.getDecl()->getDeclContext()); + return vd->getDeclContext()->getGenericSignatureOfContext(); } llvm_unreachable("Unhandled SILDeclRefKind in switch."); @@ -2107,12 +2094,16 @@ getAnyFunctionRefFromCapture(CapturedValue capture) { } bool -TypeConverter::hasLoweredLocalCaptures(AnyFunctionRef fn) { +TypeConverter::hasLoweredLocalCaptures(SILDeclRef fn) { return !getLoweredLocalCaptures(fn).getCaptures().empty(); } CaptureInfo -TypeConverter::getLoweredLocalCaptures(AnyFunctionRef fn) { +TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) { + fn.isForeign = 0; + fn.isCurried = 0; + fn.isDirectReference = 0; + // See if we've cached the lowered capture list for this function. auto found = LoweredCaptures.find(fn); if (found != LoweredCaptures.end()) @@ -2132,6 +2123,7 @@ TypeConverter::getLoweredLocalCaptures(AnyFunctionRef fn) { std::function collectCaptures; std::function collectFunctionCaptures; + std::function collectConstantCaptures; collectCaptures = [&](const CaptureInfo &captureInfo) { if (captureInfo.hasGenericParamCaptures()) @@ -2262,7 +2254,10 @@ TypeConverter::getLoweredLocalCaptures(AnyFunctionRef fn) { collectCaptures(curFn.getCaptureInfo()); - // Also visit default argument captures. + // A function's captures also include its default arguments, because + // when we reference a function we don't track which default arguments + // are referenced too. + // // FIXME: This should be more fine-grained -- we should only need the // captures for default arguments that are actually referenced. if (auto *AFD = curFn.getAbstractFunctionDecl()) { @@ -2272,7 +2267,27 @@ TypeConverter::getLoweredLocalCaptures(AnyFunctionRef fn) { } } }; - collectFunctionCaptures(fn); + + collectConstantCaptures = [&](SILDeclRef curFn) { + if (curFn.isDefaultArgGenerator()) { + if (auto *afd = dyn_cast(curFn.getDecl())) { + auto *param = getParameterAt(afd, curFn.defaultArgIndex); + if (param->getDefaultValue()) + collectCaptures(param->getDefaultArgumentCaptureInfo()); + return; + } + + if (curFn.getDecl()->getInnermostDeclContext() + ->getGenericSignatureOfContext()) + capturesGenericParams = true; + + return; + } + + collectFunctionCaptures(*curFn.getAnyFunctionRef()); + }; + + collectConstantCaptures(fn); SmallVector resultingCaptures; for (auto capturePair : captures) { @@ -2518,7 +2533,7 @@ TypeConverter::getInterfaceBoxTypeForCapture(ValueDecl *captured, bool isMutable) { auto &C = M.getASTContext(); auto signature = getCanonicalSignatureOrNull( - getEffectiveGenericSignature(captured->getDeclContext())); + captured->getDeclContext()->getGenericSignatureOfContext()); // If the type is not dependent at all, we can form a concrete box layout. // We don't need to capture the generic environment. @@ -2606,7 +2621,7 @@ CanSILBoxType TypeConverter::getBoxTypeForEnumElement(SILType enumType, Context.getLazyResolver()->resolveDeclSignature(elt); auto boxSignature = getCanonicalSignatureOrNull( - getEffectiveGenericSignature(enumDecl)); + enumDecl->getGenericSignature()); if (boxSignature == CanGenericSignature()) { auto eltIntfTy = elt->getArgumentInterfaceType(); diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index c6a6756c0b7ee..11a9c69039512 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -1111,7 +1111,7 @@ class SILGenApply : public Lowering::ExprVisitor { .asForeign(!isConstructorWithGeneratedAllocatorThunk(e->getDecl()) && requiresForeignEntryPoint(e->getDecl())); - auto captureInfo = SGF.SGM.Types.getLoweredLocalCaptures(afd); + auto captureInfo = SGF.SGM.Types.getLoweredLocalCaptures(constant); if (afd->getDeclContext()->isLocalContext() && !captureInfo.hasGenericParamCaptures()) subs = SubstitutionMap(); @@ -1142,7 +1142,8 @@ class SILGenApply : public Lowering::ExprVisitor { // If the decl ref requires captures, emit the capture params. if (!captureInfo.getCaptures().empty()) { SmallVector captures; - SGF.emitCaptures(e, afd, CaptureEmission::ImmediateApplication, + SGF.emitCaptures(e, SILDeclRef(afd), + CaptureEmission::ImmediateApplication, captures); applyCallee->setCaptures(std::move(captures)); } @@ -1163,7 +1164,7 @@ class SILGenApply : public Lowering::ExprVisitor { // really producing a closure object. SILDeclRef constant(e); - auto captureInfo = SGF.SGM.M.Types.getLoweredLocalCaptures(e); + auto captureInfo = SGF.SGM.M.Types.getLoweredLocalCaptures(constant); SubstitutionMap subs; if (captureInfo.hasGenericParamCaptures()) @@ -1174,7 +1175,7 @@ class SILGenApply : public Lowering::ExprVisitor { // If the closure requires captures, emit them. if (!captureInfo.getCaptures().empty()) { SmallVector captures; - SGF.emitCaptures(e, e, CaptureEmission::ImmediateApplication, + SGF.emitCaptures(e, constant, CaptureEmission::ImmediateApplication, captures); applyCallee->setCaptures(std::move(captures)); } @@ -5198,7 +5199,7 @@ static Callee getBaseAccessorFunctionRef(SILGenFunction &SGF, // The accessor might be a local function that does not capture any // generic parameters, in which case we don't want to pass in any // substitutions. - auto captureInfo = SGF.SGM.Types.getLoweredLocalCaptures(decl); + auto captureInfo = SGF.SGM.Types.getLoweredLocalCaptures(constant); if (decl->getDeclContext()->isLocalContext() && !captureInfo.hasGenericParamCaptures()) { subs = SubstitutionMap(); @@ -5260,11 +5261,10 @@ emitSpecializedAccessorFunctionRef(SILGenFunction &SGF, substitutions, isOnSelfParameter); // Collect captures if the accessor has them. - auto accessorFn = cast(constant.getDecl()); - if (SGF.SGM.M.Types.hasLoweredLocalCaptures(accessorFn)) { + if (SGF.SGM.M.Types.hasLoweredLocalCaptures(constant)) { assert(!selfValue && "local property has self param?!"); SmallVector captures; - SGF.emitCaptures(loc, accessorFn, CaptureEmission::ImmediateApplication, + SGF.emitCaptures(loc, constant, CaptureEmission::ImmediateApplication, captures); callee.setCaptures(std::move(captures)); } diff --git a/lib/SILGen/SILGenConstructor.cpp b/lib/SILGen/SILGenConstructor.cpp index cebc6627e6c28..a9cbe49fb156f 100644 --- a/lib/SILGen/SILGenConstructor.cpp +++ b/lib/SILGen/SILGenConstructor.cpp @@ -288,7 +288,8 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) { emitProlog(ctor->getParameters(), /*selfParam=*/nullptr, ctor->getResultInterfaceType(), ctor, - ctor->hasThrows()); + ctor->hasThrows(), + ctor->getThrowsLoc()); emitConstructorMetatypeArg(*this, ctor); // Create a basic block to jump to for the implicit 'self' return. @@ -638,7 +639,7 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) { // FIXME: Handle self along with the other body patterns. uint16_t ArgNo = emitProlog(ctor->getParameters(), /*selfParam=*/nullptr, TupleType::getEmpty(F.getASTContext()), ctor, - ctor->hasThrows()); + ctor->hasThrows(), ctor->getThrowsLoc()); SILType selfTy = getLoweredLoadableType(selfDecl->getType()); ManagedValue selfArg = B.createInputFunctionArgument(selfTy, selfDecl); diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index fe0183a7bb5fe..9103f65ea51be 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -1541,8 +1541,7 @@ ManagedValue emitCFunctionPointer(SILGenFunction &SGF, SILConstantInfo constantInfo = SGF.getConstantInfo(constant); // C function pointers cannot capture anything from their context. - auto captures = SGF.SGM.Types.getLoweredLocalCaptures( - *constant.getAnyFunctionRef()); + auto captures = SGF.SGM.Types.getLoweredLocalCaptures(constant); if (captures.hasGenericParamCaptures() || captures.hasDynamicSelfCapture() || diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index f8e73177f9915..65bed08759832 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -169,7 +169,7 @@ SILGenFunction::emitSiblingMethodRef(SILLocation loc, } void SILGenFunction::emitCaptures(SILLocation loc, - AnyFunctionRef closure, + SILDeclRef closure, CaptureEmission purpose, SmallVectorImpl &capturedArgs) { auto captureInfo = SGM.Types.getLoweredLocalCaptures(closure); @@ -230,8 +230,21 @@ void SILGenFunction::emitCaptures(SILLocation loc, if (found == VarLocs.end()) { auto &Diags = getASTContext().Diags; - Diags.diagnose(closure.getLoc(), - closure.isDeferBody() + SourceLoc loc; + bool isDeferBody; + if (closure.kind == SILDeclRef::Kind::DefaultArgGenerator) { + auto *param = getParameterAt(closure.getDecl(), + closure.defaultArgIndex); + loc = param->getLoc(); + isDeferBody = false; + } else { + auto f = *closure.getAnyFunctionRef(); + loc = f.getLoc(); + isDeferBody = f.isDeferBody(); + } + + Diags.diagnose(loc, + isDeferBody ? diag::capture_before_declaration_defer : diag::capture_before_declaration, vd->getBaseName().getIdentifier()); @@ -360,10 +373,7 @@ ManagedValue SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant, CanType expectedType, SubstitutionMap subs) { - auto closure = *constant.getAnyFunctionRef(); - auto captureInfo = closure.getCaptureInfo(); - auto loweredCaptureInfo = SGM.Types.getLoweredLocalCaptures(closure); - auto hasCaptures = SGM.Types.hasLoweredLocalCaptures(closure); + auto loweredCaptureInfo = SGM.Types.getLoweredLocalCaptures(constant); auto constantInfo = getConstantInfo(constant); SILValue functionRef = emitGlobalFunctionRef(loc, constant, constantInfo); @@ -372,6 +382,7 @@ SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant, // Apply substitutions. auto pft = constantInfo.SILFnType; + auto closure = *constant.getAnyFunctionRef(); auto *dc = closure.getAsDeclContext()->getParent(); if (dc->isLocalContext() && !loweredCaptureInfo.hasGenericParamCaptures()) { // If the lowered function type is not polymorphic but we were given @@ -396,11 +407,12 @@ SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant, // globals, but we still need to mark them as escaping so that DI can flag // uninitialized uses. if (this == SGM.TopLevelSGF) { + auto captureInfo = closure.getCaptureInfo(); SGM.emitMarkFunctionEscapeForTopLevelCodeGlobals( loc, captureInfo); } - if (!hasCaptures && !wasSpecialized) { + if (loweredCaptureInfo.getCaptures().empty() && !wasSpecialized) { auto result = ManagedValue::forUnmanaged(functionRef); return emitOrigToSubstValue(loc, result, AbstractionPattern(expectedType), @@ -408,7 +420,7 @@ SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant, } SmallVector capturedArgs; - emitCaptures(loc, closure, CaptureEmission::PartialApplication, + emitCaptures(loc, constant, CaptureEmission::PartialApplication, capturedArgs); // The partial application takes ownership of the context parameters. @@ -440,8 +452,9 @@ SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant, void SILGenFunction::emitFunction(FuncDecl *fd) { MagicFunctionName = SILGenModule::getMagicFunctionName(fd); - emitProlog(fd, fd->getParameters(), fd->getImplicitSelfDecl(), - fd->getResultInterfaceType(), fd->hasThrows()); + auto captureInfo = SGM.M.Types.getLoweredLocalCaptures(SILDeclRef(fd)); + emitProlog(captureInfo, fd->getParameters(), fd->getImplicitSelfDecl(), fd, + fd->getResultInterfaceType(), fd->hasThrows(), fd->getThrowsLoc()); Type resultTy = fd->mapTypeIntoContext(fd->getResultInterfaceType()); prepareEpilog(resultTy, fd->hasThrows(), CleanupLocation(fd)); @@ -457,8 +470,10 @@ void SILGenFunction::emitClosure(AbstractClosureExpr *ace) { MagicFunctionName = SILGenModule::getMagicFunctionName(ace); auto resultIfaceTy = ace->getResultType()->mapTypeOutOfContext(); - emitProlog(ace, ace->getParameters(), /*selfParam=*/nullptr, - resultIfaceTy, ace->isBodyThrowing()); + auto captureInfo = SGM.M.Types.getLoweredLocalCaptures( + SILDeclRef(ace)); + emitProlog(captureInfo, ace->getParameters(), /*selfParam=*/nullptr, + ace, resultIfaceTy, ace->isBodyThrowing(), ace->getLoc()); prepareEpilog(ace->getResultType(), ace->isBodyThrowing(), CleanupLocation(ace)); emitProfilerIncrement(ace); @@ -669,10 +684,13 @@ void SILGenFunction::emitGeneratorFunction(SILDeclRef function, Expr *value, } } + CaptureInfo captureInfo; + if (function.getAnyFunctionRef()) + captureInfo = SGM.M.Types.getLoweredLocalCaptures(function); auto *dc = function.getDecl()->getInnermostDeclContext(); auto interfaceType = value->getType()->mapTypeOutOfContext(); - emitProlog(/*paramList=*/nullptr, /*selfParam=*/nullptr, interfaceType, - dc, false); + emitProlog(captureInfo, /*paramList=*/nullptr, /*selfParam=*/nullptr, + dc, interfaceType, /*throws=*/false, SourceLoc()); if (EmitProfilerIncrement) emitProfilerIncrement(value); prepareEpilog(value->getType(), false, CleanupLocation::get(Loc)); @@ -702,7 +720,7 @@ void SILGenFunction::emitGeneratorFunction(SILDeclRef function, VarDecl *var) { } emitProlog(/*paramList*/ nullptr, /*selfParam*/ nullptr, interfaceType, dc, - false); + /*throws=*/false, SourceLoc()); prepareEpilog(varType, false, CleanupLocation::get(loc)); auto pbd = var->getParentPatternBinding(); diff --git a/lib/SILGen/SILGenFunction.h b/lib/SILGen/SILGenFunction.h index 0fb2b39cb2254..4187c86852c06 100644 --- a/lib/SILGen/SILGenFunction.h +++ b/lib/SILGen/SILGenFunction.h @@ -770,12 +770,14 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction /// emitProlog - Generates prolog code to allocate and clean up mutable /// storage for closure captures and local arguments. - void emitProlog(AnyFunctionRef TheClosure, + void emitProlog(const CaptureInfo &captureInfo, ParameterList *paramList, ParamDecl *selfParam, - Type resultType, bool throws); + DeclContext *DC, Type resultType, + bool throws, SourceLoc throwsLoc); /// returns the number of variables in paramPatterns. uint16_t emitProlog(ParameterList *paramList, ParamDecl *selfParam, - Type resultType, DeclContext *DeclCtx, bool throws); + Type resultType, DeclContext *DC, + bool throws, SourceLoc throwsLoc); /// Create SILArguments in the entry block that bind a single value /// of the given parameter suitably for being forwarded. @@ -1211,7 +1213,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction bool isBaseGuaranteed = false); void emitCaptures(SILLocation loc, - AnyFunctionRef TheClosure, + SILDeclRef closure, CaptureEmission purpose, SmallVectorImpl &captures); diff --git a/lib/SILGen/SILGenProlog.cpp b/lib/SILGen/SILGenProlog.cpp index bc9be3f02f5db..656ad9cdbf33c 100644 --- a/lib/SILGen/SILGenProlog.cpp +++ b/lib/SILGen/SILGenProlog.cpp @@ -338,7 +338,7 @@ void SILGenFunction::bindParametersForForwarding(const ParameterList *params, } static void emitCaptureArguments(SILGenFunction &SGF, - AnyFunctionRef closure, + GenericSignature *origGenericSig, CapturedValue capture, uint16_t ArgNo) { @@ -349,9 +349,9 @@ static void emitCaptureArguments(SILGenFunction &SGF, // Local function to get the captured variable type within the capturing // context. auto getVarTypeInCaptureContext = [&]() -> Type { - auto interfaceType = VD->getInterfaceType(); - return GenericEnvironment::mapTypeIntoContext( - closure.getGenericEnvironment(), interfaceType); + auto interfaceType = VD->getInterfaceType()->getCanonicalType( + origGenericSig); + return SGF.F.mapTypeIntoContext(interfaceType); }; auto expansion = SGF.F.getResilienceExpansion(); @@ -420,12 +420,15 @@ static void emitCaptureArguments(SILGenFunction &SGF, } } -void SILGenFunction::emitProlog(AnyFunctionRef TheClosure, +void SILGenFunction::emitProlog(const CaptureInfo &captureInfo, ParameterList *paramList, ParamDecl *selfParam, - Type resultType, bool throws) { + DeclContext *DC, + Type resultType, + bool throws, + SourceLoc throwsLoc) { uint16_t ArgNo = emitProlog(paramList, selfParam, resultType, - TheClosure.getAsDeclContext(), throws); + DC, throws, throwsLoc); // Emit an unreachable instruction if a parameter type is // uninhabited @@ -442,7 +445,6 @@ void SILGenFunction::emitProlog(AnyFunctionRef TheClosure, // Emit the capture argument variables. These are placed last because they // become the first curry level of the SIL function. - auto captureInfo = SGM.Types.getLoweredLocalCaptures(TheClosure); for (auto capture : captureInfo.getCaptures()) { if (capture.isDynamicSelfMetadata()) { auto selfMetatype = MetatypeType::get( @@ -457,8 +459,7 @@ void SILGenFunction::emitProlog(AnyFunctionRef TheClosure, if (capture.isOpaqueValue()) { OpaqueValueExpr *opaqueValue = capture.getOpaqueValue(); Type type = opaqueValue->getType()->mapTypeOutOfContext(); - type = GenericEnvironment::mapTypeIntoContext( - TheClosure.getGenericEnvironment(), type); + type = F.mapTypeIntoContext(type); auto &lowering = getTypeLowering(type); SILType ty = lowering.getLoweredType(); SILValue val = F.begin()->createFunctionArgument(ty); @@ -471,7 +472,8 @@ void SILGenFunction::emitProlog(AnyFunctionRef TheClosure, continue; } - emitCaptureArguments(*this, TheClosure, capture, ++ArgNo); + emitCaptureArguments(*this, DC->getGenericSignatureOfContext(), + capture, ++ArgNo); } } @@ -512,7 +514,8 @@ uint16_t SILGenFunction::emitProlog(ParameterList *paramList, ParamDecl *selfParam, Type resultType, DeclContext *DC, - bool throws) { + bool throws, + SourceLoc throwsLoc) { // Create the indirect result parameters. auto *genericSig = DC->getGenericSignatureOfContext(); resultType = resultType->getCanonicalType(genericSig); @@ -533,15 +536,13 @@ uint16_t SILGenFunction::emitProlog(ParameterList *paramList, // Record the ArgNo of the artificial $error inout argument. unsigned ArgNo = emitter.getNumArgs(); if (throws) { - RegularLocation Loc = RegularLocation::getAutoGeneratedLocation(); - if (auto *AFD = dyn_cast(DC)) - Loc = AFD->getThrowsLoc(); - else if (auto *ACE = dyn_cast(DC)) - Loc = ACE->getLoc(); - auto NativeErrorTy = SILType::getExceptionType(getASTContext()); + auto NativeErrorTy = SILType::getExceptionType(getASTContext()); ManagedValue Undef = emitUndef(NativeErrorTy); SILDebugVariable DbgVar("$error", /*Constant*/ false, ++ArgNo); - B.createDebugValue(Loc, Undef.getValue(), DbgVar); + RegularLocation loc = RegularLocation::getAutoGeneratedLocation(); + if (throwsLoc.isValid()) + loc = throwsLoc; + B.createDebugValue(loc, Undef.getValue(), DbgVar); } return ArgNo; diff --git a/lib/SILGen/SILGenThunk.cpp b/lib/SILGen/SILGenThunk.cpp index 42083253d28c0..3b75c95f2df5c 100644 --- a/lib/SILGen/SILGenThunk.cpp +++ b/lib/SILGen/SILGenThunk.cpp @@ -150,7 +150,7 @@ void SILGenFunction::emitCurryThunk(SILDeclRef thunk) { auto *vd = thunk.getDecl(); if (auto *fd = dyn_cast(vd)) { - assert(!SGM.M.Types.hasLoweredLocalCaptures(fd) && + assert(!SGM.M.Types.hasLoweredLocalCaptures(SILDeclRef(fd)) && "methods cannot have captures"); (void) fd; } diff --git a/test/SILGen/default_arguments_generic.swift b/test/SILGen/default_arguments_generic.swift index 9c01a9d554ebd..c93b46190b97f 100644 --- a/test/SILGen/default_arguments_generic.swift +++ b/test/SILGen/default_arguments_generic.swift @@ -67,8 +67,8 @@ func outer(t: T) { func inner2(x: Int = 0) { _ = T.self } - // CHECK: [[ARG_GENERATOR:%.*]] = function_ref @$s25default_arguments_generic5outer1tyx_tlF6inner2L_1xySi_tlFfA_ : $@convention(thin) <τ_0_0> () -> Int - // CHECK: [[ARG:%.*]] = apply [[ARG_GENERATOR]]() : $@convention(thin) <τ_0_0> () -> Int + // CHECK: [[ARG_GENERATOR:%.*]] = function_ref @$s25default_arguments_generic5outer1tyx_tlF6inner2L_1xySi_tlFfA_ : $@convention(thin) () -> Int + // CHECK: [[ARG:%.*]] = apply [[ARG_GENERATOR]]() : $@convention(thin) () -> Int _ = inner2() } From 78ae7ac9dbf3beb10933a18026c194906233f3f1 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 18 Sep 2019 13:46:35 -0400 Subject: [PATCH 080/199] SILGen: Support for local function default argument captures Fixes , . --- lib/SILGen/SILGenExpr.cpp | 10 ++-- lib/Sema/TypeCheckCaptures.cpp | 3 +- test/SILGen/default_arguments_local.swift | 71 +++++++++++++++++++++++ 3 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 test/SILGen/default_arguments_local.swift diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 9103f65ea51be..8e1f13fc376e6 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -2189,9 +2189,6 @@ SILGenFunction::emitApplyOfDefaultArgGenerator(SILLocation loc, SILDeclRef generator = SILDeclRef::getDefaultArgGenerator(defaultArgsOwner.getDecl(), destIndex); - - // TODO: Should apply the default arg generator's captures, but Sema doesn't - // track them. auto fnRef = ManagedValue::forUnmanaged(emitGlobalFunctionRef(loc,generator)); auto fnType = fnRef.getType().castTo(); @@ -2206,8 +2203,13 @@ SILGenFunction::emitApplyOfDefaultArgGenerator(SILLocation loc, ResultPlanPtr resultPtr = ResultPlanBuilder::computeResultPlan(*this, calleeTypeInfo, loc, C); ArgumentScope argScope(*this, loc); + + SmallVector captures; + emitCaptures(loc, generator, CaptureEmission::ImmediateApplication, + captures); + return emitApply(std::move(resultPtr), std::move(argScope), loc, fnRef, - subs, {}, calleeTypeInfo, ApplyOptions::None, C); + subs, captures, calleeTypeInfo, ApplyOptions::None, C); } RValue SILGenFunction::emitApplyOfStoredPropertyInitializer( diff --git a/lib/Sema/TypeCheckCaptures.cpp b/lib/Sema/TypeCheckCaptures.cpp index f91a0e5dadf48..9cf5f41b1b99e 100644 --- a/lib/Sema/TypeCheckCaptures.cpp +++ b/lib/Sema/TypeCheckCaptures.cpp @@ -624,7 +624,8 @@ void TypeChecker::computeCaptures(AnyFunctionRef AFR) { /*isObjC=*/false); E->walk(finder); - if (finder.getDynamicSelfCaptureLoc().isValid()) { + if (!AFD->getDeclContext()->isLocalContext() && + finder.getDynamicSelfCaptureLoc().isValid()) { Context.Diags.diagnose(finder.getDynamicSelfCaptureLoc(), diag::dynamic_self_default_arg); } diff --git a/test/SILGen/default_arguments_local.swift b/test/SILGen/default_arguments_local.swift new file mode 100644 index 0000000000000..c650cee4b4d02 --- /dev/null +++ b/test/SILGen/default_arguments_local.swift @@ -0,0 +1,71 @@ + +// RUN: %target-swift-emit-silgen %s | %FileCheck %s + +// CHECK-LABEL: sil hidden [ossa] @$s23default_arguments_local5outer1x1y1z1wySi_yXlypxtlF : $@convention(thin) (Int, @guaranteed AnyObject, @in_guaranteed Any, @in_guaranteed T) -> () +func outer(x: Int, y: AnyObject, z: Any, w: T) { + func local1(x: Int = x) {} + func local2(y: AnyObject = y) {} + func local3(z: Any = z) {} + func local4(w: T = w) {} + func local5(u: U, w: T = w) {} + + // CHECK: [[FN:%.*]] = function_ref @$s23default_arguments_local5outer1x1y1z1wySi_yXlypxtlF6local1L_ACySi_tlFfA_ : $@convention(thin) (Int) -> Int + // CHECK: [[ARG:%.*]] = apply [[FN]](%0) : $@convention(thin) (Int) -> Int + // CHECK: [[LOCAL1:%.*]] = function_ref @$s23default_arguments_local5outer1x1y1z1wySi_yXlypxtlF6local1L_ACySi_tlF : $@convention(thin) (Int, Int) -> () + // CHECK: apply [[LOCAL1]]([[ARG]], %0) : $@convention(thin) (Int, Int) -> () + local1() + + // CHECK: [[FN:%.*]] = function_ref @$s23default_arguments_local5outer1x1y1z1wySi_yXlypxtlF6local2L_ADyyXl_tlFfA_ : $@convention(thin) (@guaranteed AnyObject) -> @owned AnyObject + // CHECK: [[ARG:%.*]] = apply [[FN]](%1) : $@convention(thin) (@guaranteed AnyObject) -> @owned AnyObject + // CHECK: [[LOCAL2:%.*]] = function_ref @$s23default_arguments_local5outer1x1y1z1wySi_yXlypxtlF6local2L_ADyyXl_tlF : $@convention(thin) (@guaranteed AnyObject, @guaranteed AnyObject) -> () + // CHECK: apply [[LOCAL2]]([[ARG]], %1) : $@convention(thin) (@guaranteed AnyObject, @guaranteed AnyObject) -> () + // CHECK: destroy_value [[ARG]] : $AnyObject + local2() + + // CHECK: [[BOX:%.*]] = alloc_box ${ var Any } + // CHECK: [[BOX_ADDR:%.*]] = project_box [[BOX]] : ${ var Any }, 0 + // CHECK: copy_addr %2 to [initialization] [[BOX_ADDR]] : $*Any + // CHECK: [[BOX_BORROW:%.*]] = begin_borrow [[BOX]] : ${ var Any } + // CHECK: [[FN:%.*]] = function_ref @$s23default_arguments_local5outer1x1y1z1wySi_yXlypxtlF6local3L_AEyyp_tlFfA_ : $@convention(thin) (@guaranteed { var Any }) -> @out Any + // CHECK: [[STACK:%.*]] = alloc_stack $Any + // CHECK: [[BOX2:%.*]] = alloc_box ${ var Any } + // CHECK: [[BOX2_ADDR:%.*]] = project_box [[BOX2]] : ${ var Any }, 0 + // CHECK: copy_addr %2 to [initialization] [[BOX2_ADDR]] : $*Any + // CHECK: [[BOX2_BORROW:%.*]] = begin_borrow [[BOX2]] : ${ var Any } + // CHECK: apply [[FN]]([[STACK]], [[BOX2_BORROW]]) : $@convention(thin) (@guaranteed { var Any }) -> @out Any + // CHECK: end_borrow [[BOX2_BORROW]] : ${ var Any } + // CHECK: destroy_value [[BOX2]] : ${ var Any } + // CHECK: %30 = function_ref @$s23default_arguments_local5outer1x1y1z1wySi_yXlypxtlF6local3L_AEyyp_tlF : $@convention(thin) (@in_guaranteed Any, @guaranteed { var Any }) -> () + // CHECK: apply %30([[STACK]], [[BOX_BORROW]]) : $@convention(thin) (@in_guaranteed Any, @guaranteed { var Any }) -> () + // CHECK: destroy_addr [[STACK]] : $*Any + // CHECK: dealloc_stack [[STACK]] : $*Any + // CHECK: end_borrow [[BOX_BORROW]] : ${ var Any } + // CHECK: destroy_value [[BOX]] : ${ var Any } + local3() + + local4() + + local5(u: "hi") +} + +// CHECK-LABEL: sil private [ossa] @$s23default_arguments_local5outer1x1y1z1wySi_yXlypxtlF6local1L_ACySi_tlFfA_ : $@convention(thin) (Int) -> Int +// CHECK-LABEL: sil private [ossa] @$s23default_arguments_local5outer1x1y1z1wySi_yXlypxtlF6local1L_ACySi_tlF : $@convention(thin) (Int, Int) -> () +// CHECK-LABEL: sil private [ossa] @$s23default_arguments_local5outer1x1y1z1wySi_yXlypxtlF6local2L_ADyyXl_tlFfA_ : $@convention(thin) (@guaranteed AnyObject) -> @owned AnyObject +// CHECK-LABEL: sil private [ossa] @$s23default_arguments_local5outer1x1y1z1wySi_yXlypxtlF6local2L_ADyyXl_tlF : $@convention(thin) (@guaranteed AnyObject, @guaranteed AnyObject) -> () +// CHECK-LABEL: sil private [ossa] @$s23default_arguments_local5outer1x1y1z1wySi_yXlypxtlF6local3L_AEyyp_tlFfA_ : $@convention(thin) (@guaranteed { var Any }) -> @out Any +// CHECK-LABEL: sil private [ossa] @$s23default_arguments_local5outer1x1y1z1wySi_yXlypxtlF6local3L_AEyyp_tlF : $@convention(thin) (@in_guaranteed Any, @guaranteed { var Any }) -> () +// CHECK-LABEL: sil private [ossa] @$s23default_arguments_local5outer1x1y1z1wySi_yXlypxtlF6local4L_AFyx_tlF : $@convention(thin) (@in_guaranteed T, @guaranteed <τ_0_0> { var τ_0_0 } ) -> () +// CHECK-LABEL: sil private [ossa] @$s23default_arguments_local5outer1x1y1z1wySi_yXlypxtlF6local5L_1uAFyqd___xtr__lFfA0_ : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } ) -> @out T + +class ArtClass { + // CHECK-LABEL: sil hidden [ossa] @$s23default_arguments_local8ArtClassC10selfMethod1uyqd___tlF : $@convention(method) (@in_guaranteed U, @guaranteed ArtClass) -> () + func selfMethod(u: U) { + // CHECK-LABEL: sil private [ossa] @$s23default_arguments_local8ArtClassC10selfMethod1uyqd___tlF0C0L_1vAE1syqd0___qd__Sitr___lFfA1_ : $@convention(thin) (@thick @dynamic_self ArtClass.Type) -> Int + // CHECK-LABEL: sil private [ossa] @$s23default_arguments_local8ArtClassC10selfMethod1uyqd___tlF0C0L_1vAE1syqd0___qd__Sitr___lF : $@convention(thin) (@in_guaranteed V, @in_guaranteed U, Int, @thick @dynamic_self ArtClass.Type) -> () + func local(v: V, u: U, s: Int = Self.intMethod()) {} + } + + static func intMethod() -> Int { + return 0 + } +} From 761b02949a8c1f462bc3dcb3939d0062f53bfcf6 Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Wed, 18 Sep 2019 11:43:35 -0700 Subject: [PATCH 081/199] ReflectionContext: Remove platform #ifs for image format checks. In principle, swift-reflection-* ought to work with cross-compiled binaries. Dispatch out to reading MachO, PE, or ELF section metadata based on the magic of an image passed to `addImage` instead of using #ifs to pick an implementation based on the host platform. (This still doesn't fully address other host/target differences like word size or endianness, but is progress toward making the tool target-agnostic.) --- include/swift/Reflection/ReflectionContext.h | 67 ++++++++++++-------- 1 file changed, 42 insertions(+), 25 deletions(-) diff --git a/include/swift/Reflection/ReflectionContext.h b/include/swift/Reflection/ReflectionContext.h index 9ea52b185dac9..a27f3328714e2 100644 --- a/include/swift/Reflection/ReflectionContext.h +++ b/include/swift/Reflection/ReflectionContext.h @@ -123,7 +123,6 @@ class ReflectionContext return sizeof(StoredPointer) * 2; } -#if defined(__APPLE__) && defined(__MACH__) template bool readMachOSections(RemoteAddress ImageStart) { auto Buf = this->getReader().readBytes(ImageStart, sizeof(typename T::Header)); @@ -277,22 +276,6 @@ class ReflectionContext return true; } - bool addImage(RemoteAddress ImageStart) { - // We start reading 4 bytes. The first 4 bytes are supposed to be - // the magic, so we understand whether this is a 32-bit executable or - // a 64-bit one. - auto Buf = this->getReader().readBytes(ImageStart, sizeof(uint32_t)); - if (!Buf) - return false; - auto HeaderMagic = reinterpret_cast(Buf.get()); - if (*HeaderMagic == llvm::MachO::MH_MAGIC) - return readMachOSections>(ImageStart); - if (*HeaderMagic == llvm::MachO::MH_MAGIC_64) - return readMachOSections>(ImageStart); - return false; - } - -#elif defined(_WIN32) bool readPECOFFSections(RemoteAddress ImageStart) { auto DOSHdrBuf = this->getReader().readBytes( ImageStart, sizeof(llvm::object::dos_header)); @@ -384,15 +367,13 @@ class ReflectionContext return true; } - bool addImage(RemoteAddress ImageStart) { + bool readPECOFF(RemoteAddress ImageStart) { auto Buf = this->getReader().readBytes(ImageStart, sizeof(llvm::object::dos_header)); if (!Buf) return false; auto DOSHdr = reinterpret_cast(Buf.get()); - if (!(DOSHdr->Magic[0] == 'M' && DOSHdr->Magic[1] == 'Z')) - return false; auto PEHeaderAddress = ImageStart.getAddressData() + DOSHdr->AddressOfNewExeHeader; @@ -407,7 +388,7 @@ class ReflectionContext return readPECOFFSections(ImageStart); } -#else // ELF platforms. + template bool readELFSections(RemoteAddress ImageStart) { auto Buf = this->getReader().readBytes(ImageStart, sizeof(typename T::Header)); @@ -506,8 +487,8 @@ class ReflectionContext savedBuffers.push_back(std::move(Buf)); return true; } - - bool addImage(RemoteAddress ImageStart) { + + bool readELF(RemoteAddress ImageStart) { auto Buf = this->getReader().readBytes(ImageStart, sizeof(llvm::ELF::Elf64_Ehdr)); @@ -527,12 +508,48 @@ class ReflectionContext return false; } } -#endif + + bool addImage(RemoteAddress ImageStart) { + // Read the first few bytes to look for a magic header. + auto Magic = this->getReader().readBytes(ImageStart, sizeof(uint32_t)); + if (!Magic) + return false; + + uint32_t MagicWord; + memcpy(&MagicWord, Magic.get(), sizeof(MagicWord)); + + // 32- and 64-bit Mach-O. + if (MagicWord == llvm::MachO::MH_MAGIC) { + return readMachOSections>(ImageStart); + } + + if (MagicWord == llvm::MachO::MH_MAGIC_64) { + return readMachOSections>(ImageStart); + } + + // PE. (This just checks for the DOS header; `readPECOFF` will further + // validate the existence of the PE header.) + auto MagicBytes = (const char*)Magic.get(); + if (MagicBytes[0] == 'M' && MagicBytes[1] == 'Z') { + return readPECOFF(ImageStart); + } + + // ELF. + if (MagicBytes[0] == llvm::ELF::ElfMagic[0] + && MagicBytes[1] == llvm::ELF::ElfMagic[1] + && MagicBytes[2] == llvm::ELF::ElfMagic[2] + && MagicBytes[3] == llvm::ELF::ElfMagic[3]) { + return readELF(ImageStart); + } + + // We don't recognize the format. + return false; + } void addReflectionInfo(ReflectionInfo I) { getBuilder().addReflectionInfo(I); } - + bool ownsObject(RemoteAddress ObjectAddress) { auto MetadataAddress = readMetadataFromInstance(ObjectAddress.getAddressData()); if (!MetadataAddress) From eb27a59ef2fb6ad05951d96fe1caa78b59eab99a Mon Sep 17 00:00:00 2001 From: Brent Royal-Gordon Date: Mon, 16 Sep 2019 18:34:00 -0700 Subject: [PATCH 082/199] [NFC] Add and use ASTContext::getNSCopyingDecl() --- include/swift/AST/ASTContext.h | 2 ++ include/swift/AST/KnownFoundationEntities.def | 1 - lib/AST/ASTContext.cpp | 23 ++++++++-------- lib/PrintAsObjC/DeclAndTypePrinter.cpp | 27 +++++++------------ lib/Sema/TypeCheckStorage.cpp | 22 +-------------- 5 files changed, 25 insertions(+), 50 deletions(-) diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index ef81c37c75ac8..2a236cdd64017 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -460,6 +460,8 @@ class ASTContext final { /// Retrieve the declaration of ObjectiveC.ObjCBool. StructDecl *getObjCBoolDecl() const; + /// Retrieve the declaration of Foundation.NSCopying. + ProtocolDecl *getNSCopyingDecl() const; /// Retrieve the declaration of Foundation.NSError. ClassDecl *getNSErrorDecl() const; /// Retrieve the declaration of Foundation.NSNumber. diff --git a/include/swift/AST/KnownFoundationEntities.def b/include/swift/AST/KnownFoundationEntities.def index 70303855bdae4..b9a589f443588 100644 --- a/include/swift/AST/KnownFoundationEntities.def +++ b/include/swift/AST/KnownFoundationEntities.def @@ -20,7 +20,6 @@ #endif FOUNDATION_ENTITY(NSArray) -FOUNDATION_ENTITY(NSCopying) FOUNDATION_ENTITY(NSDictionary) FOUNDATION_ENTITY(NSError) FOUNDATION_ENTITY(NSErrorPointer) diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index c1934f8f7d3e2..86c36c1353cf7 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -98,9 +98,10 @@ using AssociativityCacheType = Associativity>; #define FOR_KNOWN_FOUNDATION_TYPES(MACRO) \ - MACRO(NSError) \ - MACRO(NSNumber) \ - MACRO(NSValue) + MACRO(NSCopying, ProtocolDecl) \ + MACRO(NSError, ClassDecl) \ + MACRO(NSNumber, ClassDecl) \ + MACRO(NSValue, ClassDecl) struct OverrideSignatureKey { GenericSignature *baseMethodSig; @@ -217,9 +218,9 @@ struct ASTContext::Implementation { /// The declaration of ObjectiveC.ObjCBool. StructDecl *ObjCBoolDecl = nullptr; -#define CACHE_FOUNDATION_DECL(NAME) \ +#define CACHE_FOUNDATION_DECL(NAME, DECLTYPE) \ /** The declaration of Foundation.NAME. */ \ - ClassDecl *NAME##Decl = nullptr; + DECLTYPE *NAME##Decl = nullptr; FOR_KNOWN_FOUNDATION_TYPES(CACHE_FOUNDATION_DECL) #undef CACHE_FOUNDATION_DECL @@ -848,18 +849,18 @@ StructDecl *ASTContext::getObjCBoolDecl() const { return getImpl().ObjCBoolDecl; } -#define GET_FOUNDATION_DECL(NAME) \ -ClassDecl *ASTContext::get##NAME##Decl() const { \ +#define GET_FOUNDATION_DECL(NAME, DECLTYPE) \ +DECLTYPE *ASTContext::get##NAME##Decl() const { \ if (!getImpl().NAME##Decl) { \ if (ModuleDecl *M = getLoadedModule(Id_Foundation)) { \ /* Note: lookupQualified() will search both the Foundation module \ * and the Clang Foundation module it imports. */ \ SmallVector decls; \ M->lookupQualified(M, getIdentifier(#NAME), NL_OnlyTypes, decls); \ - if (decls.size() == 1 && isa(decls[0])) { \ - auto classDecl = cast(decls[0]); \ - if (classDecl->getGenericParams() == nullptr) { \ - getImpl().NAME##Decl = classDecl; \ + if (decls.size() == 1 && isa(decls[0])) { \ + auto decl = cast(decls[0]); \ + if (isa(decl) || decl->getGenericParams() == nullptr) { \ + getImpl().NAME##Decl = decl; \ } \ } \ } \ diff --git a/lib/PrintAsObjC/DeclAndTypePrinter.cpp b/lib/PrintAsObjC/DeclAndTypePrinter.cpp index 27dfa5730ba74..0f2d790b2f38d 100644 --- a/lib/PrintAsObjC/DeclAndTypePrinter.cpp +++ b/lib/PrintAsObjC/DeclAndTypePrinter.cpp @@ -1388,23 +1388,16 @@ class DeclAndTypePrinter::Implementation // upper-bounded keys. else if (swiftNominal == ctx.getDictionaryDecl() && isNSObjectOrAnyHashable(ctx, typeArgs[0])) { - if (ModuleDecl *M = ctx.getLoadedModule(ctx.Id_Foundation)) { - if (!owningPrinter.NSCopyingType) { - SmallVector decls; - M->lookupQualified(M, ctx.getIdentifier("NSCopying"), - NL_OnlyTypes, decls); - if (decls.size() == 1 && isa(decls[0])) { - owningPrinter.NSCopyingType = cast(decls[0]) - ->getDeclaredInterfaceType(); - } else { - owningPrinter.NSCopyingType = Type(); - } - } - if (*owningPrinter.NSCopyingType) { - rewrittenArgsBuf[0] = *owningPrinter.NSCopyingType; - rewrittenArgsBuf[1] = typeArgs[1]; - typeArgs = rewrittenArgsBuf; - } + if (!owningPrinter.NSCopyingType) { + if (auto proto = ctx.getNSCopyingDecl()) + owningPrinter.NSCopyingType = proto->getDeclaredInterfaceType(); + else + owningPrinter.NSCopyingType = Type(); + } + if (*owningPrinter.NSCopyingType) { + rewrittenArgsBuf[0] = *owningPrinter.NSCopyingType; + rewrittenArgsBuf[1] = typeArgs[1]; + typeArgs = rewrittenArgsBuf; } } diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index dfd74a50f9d3a..1a541da5441fd 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -830,30 +830,10 @@ createPropertyLoadOrCallSuperclassGetter(AccessorDecl *accessor, ctx); } -/// Look up the NSCopying protocol from the Foundation module, if present. -/// Otherwise return null. -static ProtocolDecl *getNSCopyingProtocol(ASTContext &ctx, - DeclContext *DC) { - auto foundation = ctx.getLoadedModule(ctx.Id_Foundation); - if (!foundation) - return nullptr; - - SmallVector results; - DC->lookupQualified(foundation, - ctx.getSwiftId(KnownFoundationEntity::NSCopying), - NL_QualifiedDefault | NL_KnownNonCascadingDependency, - results); - - if (results.size() != 1) - return nullptr; - - return dyn_cast(results.front()); -} - static Optional checkConformanceToNSCopying(ASTContext &ctx, VarDecl *var, Type type) { auto dc = var->getDeclContext(); - auto proto = getNSCopyingProtocol(ctx, dc); + auto proto = ctx.getNSCopyingDecl(); if (proto) { auto result = TypeChecker::conformsToProtocol(type, proto, dc, None); From 1802a5cfecf4be935febc4e2ad4d49944b5ee436 Mon Sep 17 00:00:00 2001 From: Brent Royal-Gordon Date: Wed, 18 Sep 2019 15:57:45 -0700 Subject: [PATCH 083/199] [NFC] Note limitation of KnownProtocols --- include/swift/AST/KnownProtocols.def | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/swift/AST/KnownProtocols.def b/include/swift/AST/KnownProtocols.def index 7f23e73ea1e74..7e1e58353ee8f 100644 --- a/include/swift/AST/KnownProtocols.def +++ b/include/swift/AST/KnownProtocols.def @@ -11,7 +11,8 @@ //===----------------------------------------------------------------------===// // // This file defines macros used for macro-metaprogramming with compiler-known -// protocols. +// protocols. Note that this mechanism does not look through an overlay into its +// underlying module, so it typically cannot find Objective-C protocols. // //===----------------------------------------------------------------------===// From bddb2c72df314bdab8abb850cabb6a34cf522c8e Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 18 Sep 2019 16:21:21 -0700 Subject: [PATCH 084/199] [NFC] Address review feedback from #27172 - Clean up some errant formatting mistakes. - Collapse some code that was duplicating computing the interface type. --- lib/AST/GenericSignatureBuilder.cpp | 13 +++++++------ lib/Sema/TypeCheckDecl.cpp | 20 ++++++++++++-------- lib/Sema/TypeCheckGeneric.cpp | 7 ++++--- lib/Serialization/Deserialization.cpp | 10 +--------- 4 files changed, 24 insertions(+), 26 deletions(-) diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp index 496fe14a1c1df..1bc5de3a6d623 100644 --- a/lib/AST/GenericSignatureBuilder.cpp +++ b/lib/AST/GenericSignatureBuilder.cpp @@ -3786,12 +3786,13 @@ PotentialArchetype *GenericSignatureBuilder::realizePotentialArchetype( static Type getStructuralType(TypeDecl *typeDecl) { if (auto typealias = dyn_cast(typeDecl)) { - // When we're computing requirement signatures, the structural type - // suffices. Otherwise we'll potentially try to validate incomplete - // requirements. - auto *proto = dyn_cast_or_null(typealias->getDeclContext()->getAsDecl()); - if (proto && proto->isComputingRequirementSignature()) - return typealias->getStructuralType(); + // When we're computing requirement signatures, the structural type + // suffices. Otherwise we'll potentially try to validate incomplete + // requirements. + auto *proto = dyn_cast_or_null( + typealias->getDeclContext()->getAsDecl()); + if (proto && proto->isComputingRequirementSignature()) + return typealias->getStructuralType(); return typealias->getUnderlyingType(); } diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 1edb586715d72..84d5d2fe97e7c 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -4302,16 +4302,20 @@ ExtendedTypeRequest::evaluate(Evaluator &eval, ExtensionDecl *ext) const { // Nested Hack to break cycles if this is called before validation has // finished. if (aliasDecl->hasInterfaceType()) { - auto extendedNominal = aliasDecl->getDeclaredInterfaceType()->getAnyNominal(); + auto extendedNominal = + aliasDecl->getDeclaredInterfaceType()->getAnyNominal(); if (extendedNominal) - return TypeChecker::isPassThroughTypealias(aliasDecl, aliasDecl->getUnderlyingType(), extendedNominal) - ? extendedType - : extendedNominal->getDeclaredType(); + return TypeChecker::isPassThroughTypealias( + aliasDecl, aliasDecl->getUnderlyingType(), extendedNominal) + ? extendedType + : extendedNominal->getDeclaredType(); } else { - if (auto ty = aliasDecl->getStructuralType()->getAs()) - return TypeChecker::isPassThroughTypealias(aliasDecl, ty, ty->getDecl()) - ? extendedType - : ty->getDecl()->getDeclaredType(); + if (auto ty = aliasDecl->getStructuralType() + ->getAs()) + return TypeChecker::isPassThroughTypealias(aliasDecl, ty, + ty->getDecl()) + ? extendedType + : ty->getDecl()->getDeclaredType(); } } } diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index eacb07beca341..0a65d7db6870f 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -556,7 +556,8 @@ static Type formExtensionInterfaceType( } // If we have a typealias, try to form type sugar. - if (typealias && TypeChecker::isPassThroughTypealias(typealias, typealias->getUnderlyingType(), nominal)) { + if (typealias && TypeChecker::isPassThroughTypealias( + typealias, typealias->getUnderlyingType(), nominal)) { auto typealiasSig = typealias->getGenericSignature(); SubstitutionMap subMap; if (typealiasSig) { @@ -565,10 +566,10 @@ static Type formExtensionInterfaceType( mustInferRequirements = true; } - resultType = TypeAliasType::get(typealias, parentType, subMap, - resultType); + resultType = TypeAliasType::get(typealias, parentType, subMap, resultType); } + return resultType; } diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index b02c5da5ef3b0..3b78e0795ad7b 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -2292,15 +2292,7 @@ class swift::DeclDeserializer { auto underlying = MF.getType(underlyingTypeID); alias->setUnderlyingType(underlying); - SubstitutionMap subs; - if (genericSig) { - subs = genericSig->getIdentitySubstitutionMap(); - } - Type parent; - if (DC->isTypeContext()) - parent = DC->getDeclaredInterfaceType(); - auto sugaredType = TypeAliasType::get(alias, parent, subs, underlying); - alias->setInterfaceType(MetatypeType::get(sugaredType, ctx)); + alias->computeType(); alias->setValidationToChecked(); if (auto accessLevel = getActualAccessLevel(rawAccessLevel)) From 22861ec0fd23be914688623bb2b896858f4bd6ea Mon Sep 17 00:00:00 2001 From: Ravi Kandhadai Date: Wed, 18 Sep 2019 15:12:52 -0700 Subject: [PATCH 085/199] [Constant Evaluator] Pass assert configuartion option to the evaluator to precisely evaluate Builtin.assert_configuration. Unify UnknownReason::Trap and UnknownReason::AssertionFailure error values in the constant evaluator, now that we have 'condfail_message' SIL instruction, which provides an error message for the traps. --- include/swift/AST/DiagnosticsSIL.def | 9 +- include/swift/SIL/SILConstants.h | 115 ++++++++++-------- include/swift/SILOptimizer/Utils/ConstExpr.h | 11 +- lib/SIL/SILConstants.cpp | 13 +- .../Mandatory/DataflowDiagnostics.cpp | 3 +- .../Mandatory/OSLogOptimization.cpp | 13 +- .../ConstantEvaluableSubsetChecker.cpp | 1 + .../UtilityPasses/ConstantEvaluatorTester.cpp | 3 +- lib/SILOptimizer/Utils/ConstExpr.cpp | 85 +++++++------ .../constant_evaluable_subset_test.swift | 16 +-- ...onstant_evaluable_subset_test_arch64.swift | 4 +- test/SILOptimizer/constant_evaluator_test.sil | 6 +- 12 files changed, 152 insertions(+), 127 deletions(-) diff --git a/include/swift/AST/DiagnosticsSIL.def b/include/swift/AST/DiagnosticsSIL.def index 8abc49e942b74..bda7ff6739805 100644 --- a/include/swift/AST/DiagnosticsSIL.def +++ b/include/swift/AST/DiagnosticsSIL.def @@ -377,15 +377,10 @@ NOTE(constexpr_overflow,none, "integer overflow detected", ()) NOTE(constexpr_overflow_operation,none, "operation" "%select{| performed during this call}0 overflows", (bool)) -NOTE(constexpr_trap,none, "trap detected", ()) -NOTE(constexpr_trap_operation,none, "operation" +NOTE(constexpr_trap, none, "%0", (StringRef)) +NOTE(constexpr_trap_operation, none, "operation" "%select{| performed during this call}0 traps", (bool)) -NOTE(constexpr_assertion_failed, none, "assertion failed with message: %0", - (StringRef)) -NOTE(constexpr_assertion_failed_here, none, "assertion failed" - "%select{ here| during this call}0 ", (bool)) - NOTE(constexpr_invalid_operand_seen, none, "operation with invalid operands encountered during evaluation",()) NOTE(constexpr_operand_invalid_here, none, diff --git a/include/swift/SIL/SILConstants.h b/include/swift/SIL/SILConstants.h index 1a6bd25012436..14e27e0e78323 100644 --- a/include/swift/SIL/SILConstants.h +++ b/include/swift/SIL/SILConstants.h @@ -37,6 +37,45 @@ struct UnknownSymbolicValue; extern llvm::cl::opt ConstExprLimit; +/// An abstract class that exposes functions for allocating symbolic values. +/// The implementors of this class have to determine where to allocate them and +/// and manage the lifetime of the allocated symbolic values. +class SymbolicValueAllocator { +public: + virtual ~SymbolicValueAllocator() {} + + /// Allocate raw bytes. + /// \param byteSize number of bytes to allocate. + /// \param alignment alignment for the allocated bytes. + virtual void *allocate(unsigned long byteSize, unsigned alignment) = 0; + + /// Allocate storage for a given number of elements of a specific type + /// provided as a template parameter. Precondition: \c T must have an + /// accesible zero argument constructor. + /// \param numElts number of elements of the type to allocate. + template T *allocate(unsigned numElts) { + T *res = (T *)allocate(sizeof(T) * numElts, alignof(T)); + for (unsigned i = 0; i != numElts; ++i) + new (res + i) T(); + return res; + } +}; + +/// A class that allocates symbolic values in a local bump allocator. The +/// lifetime of the bump allocator is same as the lifetime of \c this object. +class SymbolicValueBumpAllocator : public SymbolicValueAllocator { +private: + llvm::BumpPtrAllocator bumpAllocator; + +public: + SymbolicValueBumpAllocator() {} + ~SymbolicValueBumpAllocator() {} + + void *allocate(unsigned long byteSize, unsigned alignment) { + return bumpAllocator.Allocate(byteSize, alignment); + } +}; + /// When we fail to constant fold a value, this captures a reason why, /// allowing the caller to produce a specific diagnostic. The "Unknown" /// SymbolicValue representation also includes a pointer to the SILNode in @@ -58,13 +97,9 @@ class UnknownReason { /// Integer overflow detected. Overflow, - /// Unspecified trap detected. + /// Trap detected. Traps will a message as a payload. Trap, - /// Assertion failure detected. These have an associated message unlike - /// traps. - AssertionFailure, - /// An operation was applied over operands whose symbolic values were /// constants but were not valid for the operation. InvalidOperandValue, @@ -111,14 +146,20 @@ class UnknownReason { // Auxiliary information for different unknown kinds. union { SILFunction *function; - const char *failedAssertMessage; + const char *trapMessage; } payload; public: UnknownKind getKind() { return kind; } static bool isUnknownKindWithPayload(UnknownKind kind) { - return kind == UnknownKind::CalleeImplementationUnknown; + switch (kind) { + case UnknownKind::CalleeImplementationUnknown: + case UnknownKind::Trap: + return true; + default: + return false; + } } static UnknownReason create(UnknownKind kind) { @@ -141,57 +182,23 @@ class UnknownReason { return payload.function; } - static UnknownReason createAssertionFailure(const char *message, - size_t size) { - assert(message[size] == '\0' && "message must be null-terminated"); + static UnknownReason createTrap(StringRef message, + SymbolicValueAllocator &allocator) { + // Copy and null terminate the string. + size_t size = message.size(); + char *messagePtr = allocator.allocate(size + 1); + std::uninitialized_copy(message.begin(), message.end(), messagePtr); + messagePtr[size] = '\0'; + UnknownReason reason; - reason.kind = UnknownKind::AssertionFailure; - reason.payload.failedAssertMessage = message; + reason.kind = UnknownKind::Trap; + reason.payload.trapMessage = messagePtr; return reason; } - const char *getAssertionFailureMessage() { - assert(kind == UnknownKind::AssertionFailure); - return payload.failedAssertMessage; - } -}; - -/// An abstract class that exposes functions for allocating symbolic values. -/// The implementors of this class have to determine where to allocate them and -/// and manage the lifetime of the allocated symbolic values. -class SymbolicValueAllocator { -public: - virtual ~SymbolicValueAllocator() {} - - /// Allocate raw bytes. - /// \param byteSize number of bytes to allocate. - /// \param alignment alignment for the allocated bytes. - virtual void *allocate(unsigned long byteSize, unsigned alignment) = 0; - - /// Allocate storage for a given number of elements of a specific type - /// provided as a template parameter. Precondition: \c T must have an - /// accesible zero argument constructor. - /// \param numElts number of elements of the type to allocate. - template T *allocate(unsigned numElts) { - T *res = (T *)allocate(sizeof(T) * numElts, alignof(T)); - for (unsigned i = 0; i != numElts; ++i) - new (res + i) T(); - return res; - } -}; - -/// A class that allocates symbolic values in a local bump allocator. The -/// lifetime of the bump allocator is same as the lifetime of \c this object. -class SymbolicValueBumpAllocator : public SymbolicValueAllocator { -private: - llvm::BumpPtrAllocator bumpAllocator; - -public: - SymbolicValueBumpAllocator() {} - ~SymbolicValueBumpAllocator() {} - - void *allocate(unsigned long byteSize, unsigned alignment) { - return bumpAllocator.Allocate(byteSize, alignment); + const char *getTrapMessage() { + assert(kind == UnknownKind::Trap); + return payload.trapMessage; } }; diff --git a/include/swift/SILOptimizer/Utils/ConstExpr.h b/include/swift/SILOptimizer/Utils/ConstExpr.h index 0f1437ff08f6e..cb6cac6b97a6e 100644 --- a/include/swift/SILOptimizer/Utils/ConstExpr.h +++ b/include/swift/SILOptimizer/Utils/ConstExpr.h @@ -45,6 +45,10 @@ class UnknownReason; class ConstExprEvaluator { SymbolicValueAllocator &allocator; + // Assert configuration that must be used by the evaluator. This determines + // the result of the builtin "assert_configuration". + unsigned assertConfig; + /// The current call stack, used for providing accurate diagnostics. llvm::SmallVector callStack; @@ -58,13 +62,15 @@ class ConstExprEvaluator { public: explicit ConstExprEvaluator(SymbolicValueAllocator &alloc, - bool trackCallees = false); + unsigned assertConf, bool trackCallees = false); ~ConstExprEvaluator(); explicit ConstExprEvaluator(const ConstExprEvaluator &other); SymbolicValueAllocator &getAllocator() { return allocator; } + unsigned getAssertConfig() { return assertConfig; } + void pushCallStack(SourceLoc loc) { callStack.push_back(loc); } void popCallStack() { @@ -124,7 +130,8 @@ class ConstExprStepEvaluator { /// Constructs a step evaluator given an allocator and a non-null pointer to a /// SILFunction. explicit ConstExprStepEvaluator(SymbolicValueAllocator &alloc, - SILFunction *fun, bool trackCallees = false); + SILFunction *fun, unsigned assertConf, + bool trackCallees = false); ~ConstExprStepEvaluator(); /// Evaluate an instruction in the current interpreter state. diff --git a/lib/SIL/SILConstants.cpp b/lib/SIL/SILConstants.cpp index 235b78601cd9d..4bd8bcb9b5894 100644 --- a/lib/SIL/SILConstants.cpp +++ b/lib/SIL/SILConstants.cpp @@ -656,20 +656,13 @@ void SymbolicValue::emitUnknownDiagnosticNotes(SILLocation fallbackLoc) { diagnose(ctx, triggerLoc, diag::constexpr_overflow_operation, triggerLocSkipsInternalLocs); return; - case UnknownReason::Trap: - diagnose(ctx, diagLoc, diag::constexpr_trap); + case UnknownReason::Trap: { + const char *message = unknownReason.getTrapMessage(); + diagnose(ctx, diagLoc, diag::constexpr_trap, StringRef(message)); if (emitTriggerLocInDiag) diagnose(ctx, triggerLoc, diag::constexpr_trap_operation, triggerLocSkipsInternalLocs); return; - case UnknownReason::AssertionFailure: { - const char *message = unknownReason.getAssertionFailureMessage(); - diagnose(ctx, diagLoc, diag::constexpr_assertion_failed, - StringRef(message)); - if (emitTriggerLocInDiag) - diagnose(ctx, triggerLoc, diag::constexpr_assertion_failed_here, - triggerLocSkipsInternalLocs); - return; } case UnknownReason::InvalidOperandValue: diagnose(ctx, diagLoc, diag::constexpr_invalid_operand_seen); diff --git a/lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp b/lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp index 7098b0195276e..53572a64b6d0d 100644 --- a/lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp +++ b/lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp @@ -194,7 +194,8 @@ class EmitDFDiagnostics : public SILFunctionTransform { if (M.getASTContext().LangOpts.EnableExperimentalStaticAssert) { SymbolicValueBumpAllocator allocator; - ConstExprEvaluator constantEvaluator(allocator); + ConstExprEvaluator constantEvaluator(allocator, + getOptions().AssertConfig); for (auto &BB : *getFunction()) for (auto &I : BB) diagnosePoundAssert(&I, M, constantEvaluator); diff --git a/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp b/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp index 8f4dd787d5bbf..09551d05779b2 100644 --- a/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp +++ b/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp @@ -186,9 +186,10 @@ class FoldState { SmallVector constantSILValues; public: - FoldState(SILFunction *fun, SILInstruction *beginInst, + FoldState(SILFunction *fun, unsigned assertConfig, SILInstruction *beginInst, ArrayRef endInsts) - : constantEvaluator(allocator, fun), beginInstruction(beginInst), + : constantEvaluator(allocator, fun, assertConfig), + beginInstruction(beginInst), endInstructions(endInsts.begin(), endInsts.end()) {} void addConstantSILValue(SILValue value) { @@ -627,13 +628,14 @@ static bool detectAndDiagnoseErrors(Optional errorInfo, /// Constant evaluate instructions starting from 'start' and fold the uses /// of the value 'oslogMessage'. Stop when oslogMessageValue is released. static void constantFold(SILInstruction *start, - SingleValueInstruction *oslogMessage) { + SingleValueInstruction *oslogMessage, + unsigned assertConfig) { // Initialize fold state. SmallVector lifetimeEndInsts; getLifetimeEndInstructionsOfSILValue(oslogMessage, lifetimeEndInsts); - FoldState state(start->getFunction(), start, lifetimeEndInsts); + FoldState state(start->getFunction(), assertConfig, start, lifetimeEndInsts); auto errorInfo = collectConstants(state); @@ -738,6 +740,7 @@ class OSLogOptimization : public SILFunctionTransform { /// The entry point to the transformation. void run() override { auto &fun = *getFunction(); + unsigned assertConfig = getOptions().AssertConfig; // Don't rerun optimization on deserialized functions or stdlib functions. if (fun.wasDeserializedCanonical()) { @@ -778,7 +781,7 @@ class OSLogOptimization : public SILFunctionTransform { continue; } - constantFold(interpolationStart, oslogInit); + constantFold(interpolationStart, oslogInit, assertConfig); } } }; diff --git a/lib/SILOptimizer/UtilityPasses/ConstantEvaluableSubsetChecker.cpp b/lib/SILOptimizer/UtilityPasses/ConstantEvaluableSubsetChecker.cpp index c8af3a51c4688..54ba6d88c4057 100644 --- a/lib/SILOptimizer/UtilityPasses/ConstantEvaluableSubsetChecker.cpp +++ b/lib/SILOptimizer/UtilityPasses/ConstantEvaluableSubsetChecker.cpp @@ -64,6 +64,7 @@ class ConstantEvaluableSubsetChecker : public SILModuleTransform { // Create a step evaluator and run it on the function. SymbolicValueBumpAllocator allocator; ConstExprStepEvaluator stepEvaluator(allocator, fun, + getOptions().AssertConfig, /*trackCallees*/ true); bool previousEvaluationHadFatalError = false; diff --git a/lib/SILOptimizer/UtilityPasses/ConstantEvaluatorTester.cpp b/lib/SILOptimizer/UtilityPasses/ConstantEvaluatorTester.cpp index c7370fa6bb0b9..25dc9534ba1e8 100644 --- a/lib/SILOptimizer/UtilityPasses/ConstantEvaluatorTester.cpp +++ b/lib/SILOptimizer/UtilityPasses/ConstantEvaluatorTester.cpp @@ -59,7 +59,8 @@ class ConstantEvaluatorTester : public SILFunctionTransform { llvm::errs() << "@" << fun->getName() << "\n"; SymbolicValueBumpAllocator allocator; - ConstExprStepEvaluator stepEvaluator(allocator, fun); + ConstExprStepEvaluator stepEvaluator(allocator, fun, + getOptions().AssertConfig); for (auto currI = fun->getEntryBlock()->begin();;) { auto *inst = &(*currI); diff --git a/lib/SILOptimizer/Utils/ConstExpr.cpp b/lib/SILOptimizer/Utils/ConstExpr.cpp index 71a36b29e807c..dd5d784e04818 100644 --- a/lib/SILOptimizer/Utils/ConstExpr.cpp +++ b/lib/SILOptimizer/Utils/ConstExpr.cpp @@ -449,10 +449,7 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) { default: break; case BuiltinValueKind::AssertConf: - // Pretend that asserts are enabled during evaluation so that assertion - // failures during interpretation are caught and reported. - // Int32(0) - represents a debug assert configuration. - return SymbolicValue::getInteger(0, 32); + return SymbolicValue::getInteger(evaluator.getAssertConfig(), 32); } } @@ -557,11 +554,12 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) { } return SymbolicValue::getInteger(result, evaluator.getAllocator()); } - case BuiltinValueKind::PtrToInt: { - // This is operation is supported only for string constants. This is - // because this builtin is used by the initializer of StaticString which - // is used in preconditions and assertion failures. Supporting this - // enables the evaluator to handle assertion/precondition failures. + // The two following builtins are supported only for string constants. This + // is because this builtin is used by StaticString which is used in + // preconditions and assertion failures. Supporting this enables the + // evaluator to handle assertion/precondition failures. + case BuiltinValueKind::PtrToInt: + case BuiltinValueKind::IntToPtr: { if (operand.getKind() != SymbolicValue::String) { return getUnknown(evaluator, SILValue(inst), UnknownReason::UnsupportedInstruction); @@ -721,6 +719,19 @@ ConstExprFunctionState::computeOpaqueCallResult(ApplyInst *apply, UnknownReason::createCalleeImplementationUnknown(callee)); } +/// Given a symbolic value representing an instance of StaticString, look into +/// the aggregate and extract the static string value stored inside it. +static Optional +extractStaticStringValue(SymbolicValue staticString) { + if (staticString.getKind() != SymbolicValue::Aggregate) + return None; + ArrayRef staticStringProps = staticString.getAggregateValue(); + if (staticStringProps.empty() || + staticStringProps[0].getKind() != SymbolicValue::String) + return None; + return staticStringProps[0].getStringValue(); +} + /// Given a call to a well known function, collect its arguments as constants, /// fold it, and return None. If any of the arguments are not constants, marks /// the call's results as Unknown, and return an Unknown with information about @@ -731,32 +742,32 @@ ConstExprFunctionState::computeWellKnownCallResult(ApplyInst *apply, auto conventions = apply->getSubstCalleeConv(); switch (callee) { case WellKnownFunction::AssertionFailure: { - // Extract the strings from the StaticString arguments and create a - // null-terminated assertion failure message. SmallString<4> message; - for (SILValue argument : apply->getArguments()) { + for (unsigned i = 0; i < apply->getNumArguments(); i++) { + SILValue argument = apply->getArgument(i); SymbolicValue argValue = getConstantValue(argument); - if (argValue.getKind() != SymbolicValue::Aggregate) - continue; - - ArrayRef staticStringProps = argValue.getAggregateValue(); - if (staticStringProps.empty() || - staticStringProps[0].getKind() != SymbolicValue::String) + Optional stringOpt = extractStaticStringValue(argValue); + + // The first argument is a prefix that specifies the kind of failure + // this is. + if (i == 0) { + if (stringOpt) { + message += stringOpt.getValue(); + } else { + // Use a generic prefix here, as the actual prefix is not a constant. + message += "assertion failed"; + } continue; + } - message += staticStringProps[0].getStringValue(); - message += ": "; + if (stringOpt) { + message += ": "; + message += stringOpt.getValue(); + } } - if (message.empty()) - message += ""; - - size_t size = message.size(); - char *messagePtr = evaluator.getAllocator().allocate(size + 1); - std::uninitialized_copy(message.begin(), message.end(), messagePtr); - messagePtr[size] = '\0'; return evaluator.getUnknown( (SILInstruction *)apply, - UnknownReason::createAssertionFailure(messagePtr, size)); + UnknownReason::createTrap(message, evaluator.getAllocator())); } case WellKnownFunction::StringInitEmpty: { // String.init() assert(conventions.getNumDirectSILResults() == 1 && @@ -1399,13 +1410,17 @@ ConstExprFunctionState::evaluateFlowSensitive(SILInstruction *inst) { if (isa(inst)) return None; - if (isa(inst)) { + if (CondFailInst *condFail = dyn_cast(inst)) { auto failed = getConstantValue(inst->getOperand(0)); if (failed.getKind() == SymbolicValue::Integer) { if (failed.getIntegerValue() == 0) return None; // Conditional fail actually failed. - return getUnknown(evaluator, inst, UnknownReason::Trap); + return evaluator.getUnknown( + (SILInstruction *)inst, + UnknownReason::createTrap( + (Twine("trap: ") + condFail->getMessage()).str(), + evaluator.getAllocator())); } } @@ -1649,8 +1664,8 @@ evaluateAndCacheCall(SILFunction &fn, SubstitutionMap substitutionMap, //===----------------------------------------------------------------------===// ConstExprEvaluator::ConstExprEvaluator(SymbolicValueAllocator &alloc, - bool trackCallees) - : allocator(alloc), trackCallees(trackCallees) {} + unsigned assertConf, bool trackCallees) + : allocator(alloc), assertConfig(assertConf), trackCallees(trackCallees) {} ConstExprEvaluator::~ConstExprEvaluator() {} @@ -1690,9 +1705,11 @@ void ConstExprEvaluator::computeConstantValues( ConstExprStepEvaluator::ConstExprStepEvaluator(SymbolicValueAllocator &alloc, SILFunction *fun, + unsigned assertConf, bool trackCallees) - : evaluator(alloc, trackCallees), internalState(new ConstExprFunctionState( - evaluator, fun, {}, stepsEvaluated)) { + : evaluator(alloc, assertConf, trackCallees), + internalState( + new ConstExprFunctionState(evaluator, fun, {}, stepsEvaluated)) { assert(fun); } diff --git a/test/SILOptimizer/constant_evaluable_subset_test.swift b/test/SILOptimizer/constant_evaluable_subset_test.swift index bc9923015afe4..dd1dff4b390f6 100644 --- a/test/SILOptimizer/constant_evaluable_subset_test.swift +++ b/test/SILOptimizer/constant_evaluable_subset_test.swift @@ -192,8 +192,8 @@ internal func interpretIntTruncations() -> Int8 { @_semantics("constant_evaluable") internal func testInvalidIntTruncations(a: Int32) -> Int8 { return Int8(a) - // CHECK: note: assertion failed with message: Fatal error: Not enough bits to represent the passed value: {{.*}}/Integers.swift: - // CHECK: note: assertion failed during this call + // CHECK: note: {{.*}}: Not enough bits to represent the passed value + // CHECK: note: operation performed during this call traps // CHECK: function_ref @$sSZss17FixedWidthIntegerRzrlEyxqd__cSzRd__lufC } @@ -238,8 +238,8 @@ internal func interpretSingedUnsignedConversions() -> UInt32 { @_semantics("constant_evaluable") internal func testInvalidSingedUnsignedConversions(a: Int64) -> UInt64 { return UInt64(a) - // CHECK: note: assertion failed with message: Fatal error: Negative value is not representable: {{.*}}/Integers.swift: - // CHECK: note: assertion failed during this call + // CHECK: note: {{.*}}: Negative value is not representable + // CHECK: note: operation performed during this call traps // CHECK: function_ref @$sSUss17FixedWidthIntegerRzrlEyxqd__cSzRd__lufC } @@ -341,8 +341,8 @@ func interpretIntAddOverflow() -> Int8 { @_semantics("constant_evaluable") func testDivideByZero(_ x: Int, _ y: Int) -> Int { return x / y - // CHECK: note: assertion failed with message: Fatal error: Division by zero: {{.*}}/IntegerTypes.swift: - // CHECK: note: assertion failed here + // CHECK: note: {{.*}}: Division by zero + // CHECK: note: operation traps } @_semantics("test_driver") @@ -355,8 +355,8 @@ func interpretDivideByZero() -> Int { @_semantics("constant_evaluable") func testDivideOverflow(_ x: Int8, _ y: Int8) -> Int8 { return x / y - // CHECK: note: assertion failed with message: Fatal error: Division results in an overflow: {{.*}}/IntegerTypes.swift: - // CHECK: note: assertion failed here + // CHECK: note: {{.*}}: Division results in an overflow + // CHECK: note: operation traps } @_semantics("test_driver") diff --git a/test/SILOptimizer/constant_evaluable_subset_test_arch64.swift b/test/SILOptimizer/constant_evaluable_subset_test_arch64.swift index 449a87e9d3302..917074e565744 100644 --- a/test/SILOptimizer/constant_evaluable_subset_test_arch64.swift +++ b/test/SILOptimizer/constant_evaluable_subset_test_arch64.swift @@ -70,8 +70,8 @@ internal func interpretIntTruncations() -> Int16 { @_semantics("constant_evaluable") internal func testInvalidIntTruncations(a: Int64) -> Int8 { return Int8(a) - // CHECK: note: assertion failed with message: Fatal error: Not enough bits to represent the passed value: {{.*}}/Integers.swift: - // CHECK: note: assertion failed during this call + // CHECK: note: {{.*}} Not enough bits to represent the passed value + // CHECK: note: operation performed during this call traps // CHECK: function_ref @$sSZss17FixedWidthIntegerRzrlEyxqd__cSzRd__lufC } diff --git a/test/SILOptimizer/constant_evaluator_test.sil b/test/SILOptimizer/constant_evaluator_test.sil index 3f0fc690d4601..2a3ce9566412b 100644 --- a/test/SILOptimizer/constant_evaluator_test.sil +++ b/test/SILOptimizer/constant_evaluator_test.sil @@ -1191,8 +1191,8 @@ sil [noinline] [_semantics "programtermination_point"] [canonical] @$assertionFa // CHECK-LABEL: @interpretAssertionFailure sil @interpretAssertionFailure : $@convention(thin) () -> Never { // Construct error prefix. - %0 = string_literal utf8 "prefix" - %1 = integer_literal $Builtin.Word, 6 + %0 = string_literal utf8 "error-prefix" + %1 = integer_literal $Builtin.Word, 12 %2 = builtin "ptrtoint_Word"(%0 : $Builtin.RawPointer) : $Builtin.Word %3 = integer_literal $Builtin.Int8, 2 %4 = struct $StaticString (%2 : $Builtin.Word, %1 : $Builtin.Word, %3 : $Builtin.Int8) @@ -1210,6 +1210,6 @@ sil @interpretAssertionFailure : $@convention(thin) () -> Never { %22 = function_ref @$assertionFailure : $@convention(thin) (StaticString, StaticString, UInt64) -> Never %23 = apply %22(%4, %14, %21) : $@convention(thin) (StaticString, StaticString, UInt64) -> Never - // CHECK: {{.*}}:[[@LINE-1]]:{{.*}}: note: assertion failed with message: prefix: message: + // CHECK: {{.*}}:[[@LINE-1]]:{{.*}}: note: error-prefix: message unreachable } From 42f350b682a8f4c4097c3d64c8582e18a67d4ed4 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Wed, 18 Sep 2019 17:47:18 -0700 Subject: [PATCH 086/199] utils: pass `CMAKE_Swift_COMPILER` This is the variable that the official CMake Swift support uses. Define this so that we can be forward compatible with CMake 3.15. --- utils/build-script-impl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/utils/build-script-impl b/utils/build-script-impl index 5758487f1ba6e..ec6e334583292 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -3405,6 +3405,10 @@ for host in "${ALL_HOSTS[@]}"; do continue ;; *) + cmake_options=( + ${cmake_options[@]} + -DCMAKE_Swift_COMPILER:PATH="$(build_directory_bin ${LOCAL_HOST} swift)/swiftc" + ) results_targets=( "test" ) executable_target="" ;; From f22371bf0bd8ca5591d062d1a534a55331819dd9 Mon Sep 17 00:00:00 2001 From: Andrew Trick Date: Tue, 17 Sep 2019 16:45:51 -0700 Subject: [PATCH 087/199] Add SIL SinkAddressProjections utility to avoid address phis. Enable this utility during jump-threading in SimplifyCFG. Ultimately, the SIL verifier should prevent all address-phis and we'll need to use this utility in a few more places. Fixes SIL verification failed: Unknown formal access pattern: storage --- include/swift/SILOptimizer/Utils/Local.h | 40 ++++++ lib/SILOptimizer/Transforms/SimplifyCFG.cpp | 106 ++++++++++++-- test/SILOptimizer/simplify_cfg.sil | 29 ++-- .../SILOptimizer/simplify_cfg_address_phi.sil | 136 ++++++++++++++++++ 4 files changed, 285 insertions(+), 26 deletions(-) create mode 100644 test/SILOptimizer/simplify_cfg_address_phi.sil diff --git a/include/swift/SILOptimizer/Utils/Local.h b/include/swift/SILOptimizer/Utils/Local.h index a20e86ff36776..c7a33d8afa0a5 100644 --- a/include/swift/SILOptimizer/Utils/Local.h +++ b/include/swift/SILOptimizer/Utils/Local.h @@ -372,6 +372,46 @@ class BasicBlockCloner : public SILCloner { } }; +/// Sink address projections to their out-of-block uses. This is +/// required after cloning a block and before calling +/// updateSSAAfterCloning to avoid address-type phis. +/// +/// This clones address projections at their use points, but does not +/// mutate the block containing the projections. +class SinkAddressProjections { + // Projections ordered from last to first in the chain. + SmallVector projections; + SmallSetVector inBlockDefs; + +public: + /// Check for an address projection chain ending at \p inst. Return true if + /// the given instruction is successfully analyzed. + /// + /// If \p inst does not produce an address, then return + /// true. getInBlockDefs() will contain \p inst if any of its + /// (non-address) values are used outside its block. + /// + /// If \p inst does produce an address, return true only of the + /// chain of address projections within this block is clonable at + /// their use sites. getInBlockDefs will return all non-address + /// operands in the chain that are also defined in this block. These + /// may require phis after cloning the projections. + bool analyzeAddressProjections(SILInstruction *inst); + + /// After analyzing projections, returns the list of (non-address) values + /// defined in the same block as the projections which will have uses outside + /// the block after cloning. + ArrayRef getInBlockDefs() const { + return inBlockDefs.getArrayRef(); + } + /// Clone the chain of projections at their use sites. + /// + /// Return true if anything was done. + /// + /// getInBlockProjectionOperandValues() can be called before or after cloning. + bool cloneProjections(); +}; + /// Helper function to perform SSA updates in case of jump threading. void updateSSAAfterCloning(BasicBlockCloner &Cloner, SILBasicBlock *SrcBB, SILBasicBlock *DestBB); diff --git a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp index 06971c0f91f78..64e5545b264ac 100644 --- a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp +++ b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp @@ -209,6 +209,79 @@ static bool isUsedOutsideOfBlock(SILValue V, SILBasicBlock *BB) { return false; } +// Populate 'projections' with the chain of address projections leading +// to and including 'inst'. +// +// Populate 'inBlockDefs' with all the non-address value definitions in +// the block that will be used outside this block after projection sinking. +// +// Return true on success, even if projections is empty. +bool SinkAddressProjections::analyzeAddressProjections(SILInstruction *inst) { + projections.clear(); + inBlockDefs.clear(); + + SILBasicBlock *bb = inst->getParent(); + auto pushOperandVal = [&](SILValue def) { + if (def->getParentBlock() != bb) + return true; + + if (!def->getType().isAddress()) { + inBlockDefs.insert(def); + return true; + } + if (auto *addressProj = dyn_cast(def)) { + if (addressProj->isTriviallyDuplicatable()) { + projections.push_back(addressProj); + return true; + } + } + // Can't handle a multi-value or unclonable address producer. + return false; + }; + // Check the given instruction for any address-type results. + for (auto result : inst->getResults()) { + if (!isUsedOutsideOfBlock(result, bb)) + continue; + if (!pushOperandVal(result)) + return false; + } + // Recurse upward through address projections. + for (unsigned idx = 0; idx < projections.size(); ++idx) { + // Only one address result/operand can be handled per instruction. + if (projections.size() != idx + 1) + return false; + + for (SILValue operandVal : projections[idx]->getOperandValues()) + pushOperandVal(operandVal); + } + return true; +} + +// Clone the projections gathered by 'analyzeAddressProjections' at +// their use site outside this block. +bool SinkAddressProjections::cloneProjections() { + if (projections.empty()) + return false; + + SILBasicBlock *bb = projections.front()->getParent(); + SmallVector usesToReplace; + // Clone projections in last-to-first order. + for (unsigned idx = 0; idx < projections.size(); ++idx) { + auto *oldProj = projections[idx]; + assert(oldProj->getParent() == bb); + usesToReplace.clear(); + for (Operand *use : oldProj->getUses()) { + if (use->getUser()->getParent() != bb) + usesToReplace.push_back(use); + } + for (Operand *use : usesToReplace) { + auto *newProj = oldProj->clone(use->getUser()); + use->set(cast(newProj)); + } + } + return true; +} + /// Helper function to perform SSA updates in case of jump threading. void swift::updateSSAAfterCloning(BasicBlockCloner &Cloner, SILBasicBlock *SrcBB, SILBasicBlock *DestBB) { @@ -1024,20 +1097,31 @@ bool SimplifyCFG::tryJumpThreading(BranchInst *BI) { // If it looks potentially interesting, decide whether we *can* do the // operation and whether the block is small enough to be worth duplicating. int copyCosts = 0; - for (auto &Inst : *DestBB) { - copyCosts += getThreadingCost(&Inst); + SinkAddressProjections sinkProj; + for (auto ii = DestBB->begin(), ie = DestBB->end(); ii != ie;) { + copyCosts += getThreadingCost(&*ii); if (ThreadingBudget <= copyCosts) return false; - // We need to update ssa if a value is used outside the duplicated block. - if (!NeedToUpdateSSA) { - for (auto result : Inst.getResults()) { - if (isUsedOutsideOfBlock(result, DestBB)) { - NeedToUpdateSSA = true; - break; - } - } - } + // If this is an address projection with outside uses, sink it before + // checking for SSA update. + if (!sinkProj.analyzeAddressProjections(&*ii)) + return false; + + sinkProj.cloneProjections(); + // After cloning check if any of the non-address defs in the cloned block + // (including the current instruction) now have uses outside the + // block. Do this even if nothing was cloned. + if (!sinkProj.getInBlockDefs().empty()) + NeedToUpdateSSA = true; + + auto nextII = std::next(ii); + recursivelyDeleteTriviallyDeadInstructions( + &*ii, false, [&nextII](SILInstruction *deadInst) { + if (deadInst->getIterator() == nextII) + ++nextII; + }); + ii = nextII; } // Don't jump thread through a potential header - this can produce irreducible diff --git a/test/SILOptimizer/simplify_cfg.sil b/test/SILOptimizer/simplify_cfg.sil index 8573a3dd2633a..027811125ccf3 100644 --- a/test/SILOptimizer/simplify_cfg.sil +++ b/test/SILOptimizer/simplify_cfg.sil @@ -1425,24 +1425,24 @@ bb6(%r : $Int32): // CHECK: bb0: // CHECK-NEXT: cond_br undef, bb1, bb2 // CHECK: bb1: -// CHECK-NEXT: cond_br undef, bb3, bb4 +// CHECK: enum $Optional, #Optional.none!enumelt +// CHECK: br bb3 // CHECK: bb2: +// CHECK: integer_literal $Builtin.Int32, 0 +// CHECK: enum $Optional, #Optional.some!enumelt.1 +// CHECK: br bb3 +// CHECK: bb3 // CHECK: integer_literal {{.*}}, 27 -// CHECK: br bb5 -// CHECK: bb3: -// CHECK: br bb4 -// CHECK: bb4: // CHECK: integer_literal {{.*}}, 28 -// CHECK: br bb5 -// CHECK: bb5({{.*}}): -// CHECK-NEXT: return +// CHECK: return sil @jumpthread_switch_enum4 : $@convention(thin) () -> Builtin.Int32 { bb0: + %c0 = builtin "assert_configuration"() : $Builtin.Int32 cond_br undef, bb1, bb2 bb1: %4 = enum $Optional, #Optional.none!enumelt - cond_br undef, bb3(%4 : $Optional), bb4(%4 : $Optional) + cond_br undef, bb3(%4 : $Optional), bb4(%4 : $Optional, %c0 : $Builtin.Int32) bb2: %6 = integer_literal $Builtin.Int32, 0 @@ -1454,23 +1454,22 @@ bb2: bb3(%10 : $Optional): // Some instruction which is not "trivial" %c1 = builtin "assert_configuration"() : $Builtin.Int32 - br bb4(%10 : $Optional) - + br bb4(%10 : $Optional, %c1 : $Builtin.Int32) -bb4(%13 : $Optional): +bb4(%13 : $Optional, %carg1 : $Builtin.Int32): switch_enum %13 : $Optional, case #Optional.some!enumelt.1: bb5, case #Optional.none!enumelt: bb6 bb5: %r1 = integer_literal $Builtin.Int32, 27 %c2 = builtin "assert_configuration"() : $Builtin.Int32 - br bb7(%r1 : $Builtin.Int32) + br bb7(%r1 : $Builtin.Int32, %c2 : $Builtin.Int32) bb6: %r2 = integer_literal $Builtin.Int32, 28 %c3 = builtin "assert_configuration"() : $Builtin.Int32 - br bb7(%r2 : $Builtin.Int32) + br bb7(%r2 : $Builtin.Int32, %c3 : $Builtin.Int32) -bb7(%r : $Builtin.Int32): +bb7(%r : $Builtin.Int32, %carg2 : $Builtin.Int32): return %r : $Builtin.Int32 } diff --git a/test/SILOptimizer/simplify_cfg_address_phi.sil b/test/SILOptimizer/simplify_cfg_address_phi.sil new file mode 100644 index 0000000000000..438ee2cbdf246 --- /dev/null +++ b/test/SILOptimizer/simplify_cfg_address_phi.sil @@ -0,0 +1,136 @@ +// RUN: %target-sil-opt -enable-objc-interop -enable-sil-verify-all %s -jumpthread-simplify-cfg | %FileCheck %s +// +// Test SimplifyCFG's handling of address-type phis. In other words, makes sure it doesn't create them at all! + +sil_stage canonical + +import Builtin +import Swift +import SwiftShims + +class C { + @_hasStorage @_hasInitialValue var field: Int { get set } + @objc deinit + init() +} + +sil @getC : $@convention(thin) () -> C + +// Test that jump threading sinks a ref_element_addr, generating a +// non-address phi for its operand. +// +// The retain on separate paths followed by a merged release, and +// target block with a conditional branch are necessary just to get +// jump threading to kick in. +// +// CHECK-LABEL: sil @testJumpThreadRefEltLoop : $@convention(thin) () -> () { +// CHECK: bb0 +// CHECK: function_ref @getC : $@convention(thin) () -> C +// CHECK: cond_br undef, bb1, bb2 +// CHECK: bb1: +// CHECK: [[C1:%.*]] = apply %0() : $@convention(thin) () -> C +// CHECK: strong_retain [[C1]] : $C +// CHECK: strong_release [[C1]] : $C +// CHECK: br bb3([[C1]] : $C) +// CHECK: bb2: +// CHECK: [[C2:%.*]] = apply %0() : $@convention(thin) () -> C +// CHECK: strong_retain [[C2]] : $C +// CHECK: strong_release [[C2]] : $C +// CHECK: br bb3([[C2]] : $C) +// CHECK: bb3([[PHI:%.*]] : $C): +// CHECK: [[ADR:%.*]] = ref_element_addr [[PHI]] : $C, #C.field +// CHECK: begin_access [read] [dynamic] [[ADR]] : $*Int +// CHECK: load +// CHECK: end_access +// CHECK-LABEL: } // end sil function 'testJumpThreadRefEltLoop' +sil @testJumpThreadRefEltLoop : $@convention(thin) () -> () { +bb0: + %f = function_ref @getC : $@convention(thin) () -> C + cond_br undef, bb1, bb2 + +bb1: + %c1 = apply %f() : $@convention(thin) ()->C + strong_retain %c1 : $C + br bb3(%c1 : $C) + +bb2: + %c2 = apply %f() : $@convention(thin) ()->C + strong_retain %c2 : $C + br bb3(%c2 : $C) + +bb3(%arg : $C): + strong_release %arg : $C + %18 = ref_element_addr %arg : $C, #C.field + br bb4 + +bb4: + %19 = begin_access [read] [dynamic] %18 : $*Int + %20 = load %19 : $*Int + end_access %19 : $*Int + cond_br undef, bb4, bb5 + +bb5: + %z = tuple () + return %z : $() +} + +// Test that jump threading sinks a +// ref_tail_addr->index_addr->struct_element_addr chain and generates +// a phi for the index_addr's index operand. +// +// The retain on separate paths followed by a merged release, and +// target block with a conditional branch are necessary just to get +// jump threading to kick in. +// +// CHECK-LABEL: sil @testJumpThreadIndex : $@convention(thin) (__ContiguousArrayStorageBase, Builtin.Int64) -> Builtin.Int32 { +// CHECK: bb0(%0 : $__ContiguousArrayStorageBase, %1 : $Builtin.Int64): +// CHECK: cond_br undef, bb1, bb2 +// CHECK: bb1: +// CHECK: apply +// CHECK: strong_retain +// CHECK: strong_release +// CHECK: [[IDX1:%.*]] = builtin "truncOrBitCast_Int64_Word"(%1 : $Builtin.Int64) : $Builtin.Word +// CHECK: br bb3([[IDX1]] : $Builtin.Word) +// CHECK: bb2: +// CHECK: apply +// CHECK: strong_retain +// CHECK: strong_release +// CHECK: [[IDX2:%.*]] = builtin "truncOrBitCast_Int64_Word"(%1 : $Builtin.Int64) : $Builtin.Word +// CHECK: br bb3([[IDX2]] : $Builtin.Word) +// CHECK: bb3([[PHI:%.*]] : $Builtin.Word): +// CHECK: [[TAIL:%.*]] = ref_tail_addr %0 : $__ContiguousArrayStorageBase, $Int32 +// CHECK: [[ELT:%.*]] = index_addr [[TAIL]] : $*Int32, %14 : $Builtin.Word +// CHECK: [[ADR:%.*]] = struct_element_addr [[ELT]] : $*Int32, #Int32._value +// CHECK: load [[ADR]] : $*Builtin.Int32 +// CHECK: cond_br undef, bb4, bb5 +// CHECK-LABEL: } // end sil function 'testJumpThreadIndex' +sil @testJumpThreadIndex : $@convention(thin) (__ContiguousArrayStorageBase, Builtin.Int64) -> Builtin.Int32 { +bb0(%0 : $__ContiguousArrayStorageBase, %1 : $Builtin.Int64): + %f = function_ref @getC : $@convention(thin) () -> C + cond_br undef, bb1, bb2 + +bb1: + %c1 = apply %f() : $@convention(thin) ()->C + strong_retain %c1 : $C + br bb3(%c1 : $C) + +bb2: + %c2 = apply %f() : $@convention(thin) ()->C + strong_retain %c2 : $C + br bb3(%c2 : $C) + +bb3(%arg : $C): + strong_release %arg : $C + %tail = ref_tail_addr %0 : $__ContiguousArrayStorageBase, $Int32 + %idx = builtin "truncOrBitCast_Int64_Word"(%1 : $Builtin.Int64) : $Builtin.Word + %elt = index_addr %tail : $*Int32, %idx : $Builtin.Word + %adr = struct_element_addr %elt : $*Int32, #Int32._value + br bb4 + +bb4: + %val = load %adr : $*Builtin.Int32 + cond_br undef, bb4, bb5 + +bb5: + return %val : $Builtin.Int32 +} From 21426ea748a07f6d6cc837ccd52d41cce91b9d0d Mon Sep 17 00:00:00 2001 From: Brent Royal-Gordon Date: Wed, 18 Sep 2019 18:05:39 -0700 Subject: [PATCH 088/199] =?UTF-8?q?[NFC]=20[PrintAsObjC]=20Don=E2=80=99t?= =?UTF-8?q?=20cache=20NSCopyingType?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ASTContext caches the decl and the decl caches the declared interface type, so there’s no performance win, and there isn’t a convenience win anymore either. --- lib/PrintAsObjC/DeclAndTypePrinter.cpp | 10 ++-------- lib/PrintAsObjC/DeclAndTypePrinter.h | 6 ------ 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/lib/PrintAsObjC/DeclAndTypePrinter.cpp b/lib/PrintAsObjC/DeclAndTypePrinter.cpp index 0f2d790b2f38d..3df71be5f8209 100644 --- a/lib/PrintAsObjC/DeclAndTypePrinter.cpp +++ b/lib/PrintAsObjC/DeclAndTypePrinter.cpp @@ -1388,14 +1388,8 @@ class DeclAndTypePrinter::Implementation // upper-bounded keys. else if (swiftNominal == ctx.getDictionaryDecl() && isNSObjectOrAnyHashable(ctx, typeArgs[0])) { - if (!owningPrinter.NSCopyingType) { - if (auto proto = ctx.getNSCopyingDecl()) - owningPrinter.NSCopyingType = proto->getDeclaredInterfaceType(); - else - owningPrinter.NSCopyingType = Type(); - } - if (*owningPrinter.NSCopyingType) { - rewrittenArgsBuf[0] = *owningPrinter.NSCopyingType; + if (auto proto = ctx.getNSCopyingDecl()) { + rewrittenArgsBuf[0] = proto->getDeclaredInterfaceType(); rewrittenArgsBuf[1] = typeArgs[1]; typeArgs = rewrittenArgsBuf; } diff --git a/lib/PrintAsObjC/DeclAndTypePrinter.h b/lib/PrintAsObjC/DeclAndTypePrinter.h index 8e2b6b3b46498..fc7a51f137a19 100644 --- a/lib/PrintAsObjC/DeclAndTypePrinter.h +++ b/lib/PrintAsObjC/DeclAndTypePrinter.h @@ -56,12 +56,6 @@ class DeclAndTypePrinter { /// Cached for convenience. Identifier ID_CFTypeRef; - /// The protocol type 'NSCopying', or a null type if Foundation has not been - /// imported. - /// - /// Cached for convenience. - Optional NSCopyingType; - Implementation getImpl(); public: From e2a9a432209affcd5b427481795cc859bd5ae19d Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Thu, 19 Sep 2019 08:49:27 -0700 Subject: [PATCH 089/199] [sil] Teach the SILVerifier how to validate that a builtin insts are always mapped to a known builtin. The builtin instruction in SIL identifies the operation that it performs via a simple string name. This commit changes the SILVerifier so that we validate that any builtin inst can be mapped via its string name to a /true/ builtin value decl. Just tightening up the IR model. --- lib/SIL/SILVerifier.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp index 620ea9d4ee618..b701d1b7e4226 100644 --- a/lib/SIL/SILVerifier.cpp +++ b/lib/SIL/SILVerifier.cpp @@ -1630,8 +1630,16 @@ class SILVerifier : public SILVerifierBase { void checkBuiltinInst(BuiltinInst *BI) { // Check for special constraints on llvm intrinsics. - if (BI->getIntrinsicInfo().ID != llvm::Intrinsic::not_intrinsic) + if (BI->getIntrinsicInfo().ID != llvm::Intrinsic::not_intrinsic) { verifyLLVMIntrinsic(BI, BI->getIntrinsicInfo().ID); + return; + } + + // At this point, we know that we have a Builtin that is a Swift Builtin + // rather than an llvm intrinsic. Make sure our name corresponds to an + // actual ValueDecl. Otherwise, we have an invalid builtin. + require(getBuiltinValueDecl(BI->getModule().getASTContext(), BI->getName()), + "Invalid builtin name?!"); } void checkFunctionRefBaseInst(FunctionRefBaseInst *FRI) { From 0ce2434d43a6c70cf6df81e0591045b146564341 Mon Sep 17 00:00:00 2001 From: Brent Royal-Gordon Date: Wed, 18 Sep 2019 20:13:58 -0700 Subject: [PATCH 090/199] [NFC] Convert ClangImporter use to getNSCopyingDecl() --- lib/ClangImporter/ImportType.cpp | 11 +++-------- lib/ClangImporter/ImporterImpl.h | 3 --- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index e0ab429b35f9f..08f9de2ee05e7 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -2080,10 +2080,9 @@ ImportedType ClangImporter::Implementation::importMethodType( auto optKind = getOptionalKind(ImportTypeKind::Parameter, optionalityOfParam); - if (optKind == OTK_None) - swiftParamTy = getNSCopyingType(); - else - swiftParamTy = OptionalType::get(getNSCopyingType()); + swiftParamTy = SwiftContext.getNSCopyingDecl()->getDeclaredType(); + if (optKind != OTK_None) + swiftParamTy = OptionalType::get(swiftParamTy); paramIsIUO = optKind == OTK_ImplicitlyUnwrappedOptional; } else { @@ -2496,10 +2495,6 @@ static Type getNamedProtocolType(ClangImporter::Implementation &impl, return Type(); } -Type ClangImporter::Implementation::getNSCopyingType() { - return getNamedProtocolType(*this, "NSCopying"); -} - Type ClangImporter::Implementation::getNSObjectProtocolType() { return getNamedProtocolType(*this, "NSObject"); } diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index bac23850f54b9..41cbd199dffda 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -943,9 +943,6 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation /// Retrieve the NSObject protocol type. Type getNSObjectProtocolType(); - /// Retrieve the NSCopying protocol type. - Type getNSCopyingType(); - /// Determines whether the given type matches an implicit type /// bound of "Hashable", which is used to validate NSDictionary/NSSet. bool matchesHashableBound(Type type); From 20c5dff4b5b7be6c97fd4b51b6f876516f0df75e Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Wed, 10 Jul 2019 20:58:45 -0700 Subject: [PATCH 091/199] [builtin] Implement polymorphic builtins for all BUILTIN_BINARY_OPERATIONs. TLDR: This patch introduces a new kind of builtin, "a polymorphic builtin". One calls it like any other builtin, e.x.: ``` Builtin.generic_add(x, y) ``` but it has a contract: it must be specialized to a concrete builtin by the time we hit Lowered SIL. In this commit, I add support for the following generic operations: Type | Op ------------------------ FloatOrVector |FAdd FloatOrVector |FDiv FloatOrVector |FMul FloatOrVector |FRem FloatOrVector |FSub IntegerOrVector|AShr IntegerOrVector|Add IntegerOrVector|And IntegerOrVector|ExactSDiv IntegerOrVector|ExactUDiv IntegerOrVector|LShr IntegerOrVector|Mul IntegerOrVector|Or IntegerOrVector|SDiv IntegerOrVector|SRem IntegerOrVector|Shl IntegerOrVector|Sub IntegerOrVector|UDiv IntegerOrVector|Xor Integer |URem NOTE: I only implemented support for the builtins in SIL and in SILGen. I am going to implement the optimizer parts of this in a separate series of commits. DISCUSSION ---------- Today there are polymorphic like instructions in LLVM-IR. Yet, at the swift and SIL level we represent these operations instead as Builtins whose names are resolved by splatting the builtin into the name. For example, adding two things in LLVM: ``` %2 = add i64 %0, %1 %2 = add <2 x i64> %0, %1 %2 = add <4 x i64> %0, %1 %2 = add <8 x i64> %0, %1 ``` Each of the add operations are done by the same polymorphic instruction. In constrast, we splat out these Builtins in swift today, i.e.: ``` let x, y: Builtin.Int32 Builtin.add_Int32(x, y) let x, y: Builtin.Vec4xInt32 Builtin.add_Vec4xInt32(x, y) ... ``` In SIL, we translate these verbatim and then IRGen just lowers them to the appropriate polymorphic instruction. Beyond being verbose, these prevent these Builtins (which need static types) from being used in polymorphic contexts where we can guarantee that eventually a static type will be provided. In contrast, the polymorphic builtins introduced in this commit can be passed any type, with the proviso that the expert user using this feature can guarantee that before we reach Lowered SIL, the generic_add has been eliminated. This is enforced by IRGen asserting if passed such a builtin and by the SILVerifier checking that the underlying builtin is never called once the module is in Lowered SIL. In forthcoming commits, I am going to add two optimizations that give the stdlib tool writer the tools needed to use this builtin: 1. I am going to add an optimization to constant propagation that changes a "generic_*" op to the type of its argument if the argument is a type that is valid for the builtin (i.e. integer or vector). 2. I am going to teach the SILCloner how to specialize these as it inlines. This ensures that when we transparent inline, we specialize the builtin automatically and can then form SSA at -Onone using predictable memory access operations. The main implication around these polymorphic builtins are that if an author is not able to specialize the builtin, they need to ensure that after constant propagation, the generic builtin has been DCEed. The general rules are that the -Onone optimizer will constant fold branches with constant integer operands. So if one can use a bool of some sort to trigger the operation, one can be guaranteed that the code will not codegen. I am considering putting in some sort of diagnostic to ensure that the stdlib writer has a good experience (e.x. get an error instead of crashing the compiler). --- include/swift/AST/Builtins.def | 114 ++++- include/swift/AST/Builtins.h | 5 + include/swift/SIL/PatternMatch.h | 2 +- lib/AST/Builtins.cpp | 43 +- lib/IRGen/GenBuiltin.cpp | 18 +- lib/SIL/OperandOwnership.cpp | 20 + lib/SIL/SILVerifier.cpp | 4 + lib/SIL/ValueOwnership.cpp | 20 + lib/SILGen/SILGenApply.cpp | 82 +++- .../AccessEnforcementReleaseSinking.cpp | 14 +- lib/SILOptimizer/Utils/ConstantFolding.cpp | 5 +- test/SIL/polymorphic_builtins.sil | 135 ++++++ test/SILGen/polymorphic_builtins.swift | 421 ++++++++++++++++++ 13 files changed, 820 insertions(+), 63 deletions(-) create mode 100644 test/SIL/polymorphic_builtins.sil create mode 100644 test/SILGen/polymorphic_builtins.swift diff --git a/include/swift/AST/Builtins.def b/include/swift/AST/Builtins.def index 49472b61137d3..03809bcef7008 100644 --- a/include/swift/AST/Builtins.def +++ b/include/swift/AST/Builtins.def @@ -51,32 +51,98 @@ BUILTIN_CAST_OR_BITCAST_OPERATION(SExtOrBitCast, "sextOrBitCast", "n") #undef BUILTIN_CAST_OR_BITCAST_OPERATION /// Binary operations have type (T,T) -> T. +/// +/// We define two different sorts of operations varying when T is static, +/// specifically: +/// +/// 1. Overloaded statically typed operations. E.x: +/// +/// builtin "add_Vec4xInt32"(Vec4xInt32, Vec4xInt32) : Vec4xInt32. +/// +/// 2. Polymorphic typed operations that are valid only in raw SIL. By the time +/// diagnostic constant propagation runs, these must have as its operand a +/// fully specialized type. If the builtin has a type that is not one of its +/// overloaded types, diagnostic constant propagation will emit a diagnostic +/// saying the builtin's type has not been fully resolved. Otherwise, +/// diagnostic constant propagation will transform the builtin to the +/// relevant static overloaded builtin form. E.x.: +/// +/// builtin "add"(Self, Self) : Self // *error* +/// +/// OR +/// +/// builtin "generic_add"(Vec4xInt32, Vec4xInt32) : Vec4xInt32 +/// -> +/// builtin "add_Vec4xInt32"(Vec4xInt32, Vec4xInt32) : Vec4xInt32 +/// +/// NOTE: If a polymorphic typed operation is not static by the time guaranteed +/// constant propagation runs, we emit a diagnostic to inform the user (who is +/// assumed to be an expert user) to tell them the value was unspecialized. The +/// typical way this specialization occurs today is via transparent inlining +/// since the transparent inliner devirtualizes and specializes as it goes. Of +/// course this means mandatory inlining must /always/ occur before diagnostic +/// constant propagation. +/// +/// NOTE: Often times the builtin infrastructure wants to treat all +/// binary operation builtins generic or not the same way. To ensure +/// we support all use cases in the compiler, we do not declare the +/// operations as part of this builtin since often times this macro is +/// used to generic code. Instead, we stamp this out using the +/// overloaded_static, polymorphic, and all suffixed operations. #ifndef BUILTIN_BINARY_OPERATION -#define BUILTIN_BINARY_OPERATION(Id, Name, Attrs, Overload) \ - BUILTIN(Id, Name, Attrs) +#define BUILTIN_BINARY_OPERATION(Id, Name, Attrs) BUILTIN(Id, Name, Attrs) #endif -BUILTIN_BINARY_OPERATION(Add, "add", "n", IntegerOrVector) -BUILTIN_BINARY_OPERATION(FAdd, "fadd", "n", FloatOrVector) -BUILTIN_BINARY_OPERATION(And, "and", "n", IntegerOrVector) -BUILTIN_BINARY_OPERATION(AShr, "ashr", "n", IntegerOrVector) -BUILTIN_BINARY_OPERATION(LShr, "lshr", "n", IntegerOrVector) -BUILTIN_BINARY_OPERATION(Or, "or", "n", IntegerOrVector) -BUILTIN_BINARY_OPERATION(FDiv, "fdiv", "n", FloatOrVector) -BUILTIN_BINARY_OPERATION(Mul, "mul", "n", IntegerOrVector) -BUILTIN_BINARY_OPERATION(FMul, "fmul", "n", FloatOrVector) -BUILTIN_BINARY_OPERATION(SDiv, "sdiv", "n", IntegerOrVector) -BUILTIN_BINARY_OPERATION(ExactSDiv, "sdiv_exact", "n", IntegerOrVector) -BUILTIN_BINARY_OPERATION(Shl, "shl", "n", IntegerOrVector) -BUILTIN_BINARY_OPERATION(SRem, "srem", "n", IntegerOrVector) -BUILTIN_BINARY_OPERATION(Sub, "sub", "n", IntegerOrVector) -BUILTIN_BINARY_OPERATION(FSub, "fsub", "n", FloatOrVector) -BUILTIN_BINARY_OPERATION(UDiv, "udiv", "n", IntegerOrVector) -BUILTIN_BINARY_OPERATION(ExactUDiv, "udiv_exact", "n", IntegerOrVector) -BUILTIN_BINARY_OPERATION(URem, "urem", "n", Integer) -BUILTIN_BINARY_OPERATION(FRem, "frem", "n", FloatOrVector) -BUILTIN_BINARY_OPERATION(Xor, "xor", "n", IntegerOrVector) -// This builtin is an optimizer hint and always returns the first argument. -BUILTIN_BINARY_OPERATION(Expect, "int_expect", "n", Integer) + +#ifdef BUILTIN_BINARY_OPERATION_GENERIC_HELPER_STR +#error "Do not define BUILTIN_BINARY_OPERATION_GENERIC_HELPER_STR before including this .def file" +#endif + +#define BUILTIN_BINARY_OPERATION_GENERIC_HELPER_STR(NAME) #NAME + +#ifndef BUILTIN_BINARY_OPERATION_OVERLOADED_STATIC +#define BUILTIN_BINARY_OPERATION_OVERLOADED_STATIC(Id, Name, Attrs, Overload) \ + BUILTIN_BINARY_OPERATION(Id, Name, Attrs) +#endif + +#ifndef BUILTIN_BINARY_OPERATION_POLYMORPHIC +#define BUILTIN_BINARY_OPERATION_POLYMORPHIC(Id, Name, Attrs) \ + BUILTIN_BINARY_OPERATION(Id, Name, Attrs) +#endif + +// TODO: This needs a better name. We stringify generic_ in *_{OVERLOADED_STATIC,POLYMORPHIC} +#ifndef BUILTIN_BINARY_OPERATION_ALL +#define BUILTIN_BINARY_OPERATION_ALL(Id, Name, Attrs, Overload) \ + BUILTIN_BINARY_OPERATION_OVERLOADED_STATIC(Id, BUILTIN_BINARY_OPERATION_GENERIC_HELPER_STR(Name), Attrs, Overload) \ + BUILTIN_BINARY_OPERATION_POLYMORPHIC(Generic##Id, BUILTIN_BINARY_OPERATION_GENERIC_HELPER_STR(generic_##Name), Attrs) +#endif + +// NOTE: Here we need our name field to be bare. We stringify them as +// appropriately in BUILTIN_BINARY_OPERATION_{OVERLOADED_STATIC,POLYMORPHIC}. +BUILTIN_BINARY_OPERATION_ALL(Add, add, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_ALL(FAdd, fadd, "n", FloatOrVector) +BUILTIN_BINARY_OPERATION_ALL(And, and, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_ALL(AShr, ashr, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_ALL(LShr, lshr, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_ALL(Or, or, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_ALL(FDiv, fdiv, "n", FloatOrVector) +BUILTIN_BINARY_OPERATION_ALL(Mul, mul, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_ALL(FMul, fmul, "n", FloatOrVector) +BUILTIN_BINARY_OPERATION_ALL(SDiv, sdiv, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_ALL(ExactSDiv, sdiv_exact, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_ALL(Shl, shl, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_ALL(SRem, srem, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_ALL(Sub, sub, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_ALL(FSub, fsub, "n", FloatOrVector) +BUILTIN_BINARY_OPERATION_ALL(UDiv, udiv, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_ALL(ExactUDiv, udiv_exact, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_ALL(URem, urem, "n", Integer) +BUILTIN_BINARY_OPERATION_ALL(FRem, frem, "n", FloatOrVector) +BUILTIN_BINARY_OPERATION_ALL(Xor, xor, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_OVERLOADED_STATIC(Expect, "int_expect", "n", Integer) +#undef BUILTIN_BINARY_OPERATION_ALL +#undef BUILTIN_BINARY_OPERATION_POLYMORPHIC +#undef BUILTIN_BINARY_OPERATION_OVERLOADED_STATIC +#undef BUILTIN_BINARY_OPERATION_GENERIC_HELPER_STR #undef BUILTIN_BINARY_OPERATION /// These builtins are analogous the similarly named llvm intrinsics. The diff --git a/include/swift/AST/Builtins.h b/include/swift/AST/Builtins.h index 0928509774755..71f276dddd8ca 100644 --- a/include/swift/AST/Builtins.h +++ b/include/swift/AST/Builtins.h @@ -83,6 +83,11 @@ enum class BuiltinValueKind { #include "swift/AST/Builtins.def" }; +/// Returns true if this is a polymorphic builtin that is only valid +/// in raw sil and thus must be resolved to have concrete types by the +/// time we are in canonical SIL. +bool isPolymorphicBuiltin(BuiltinValueKind Id); + /// Decode the type list of a builtin (e.g. mul_Int32) and return the base /// name (e.g. "mul"). StringRef getBuiltinBaseName(ASTContext &C, StringRef Name, diff --git a/include/swift/SIL/PatternMatch.h b/include/swift/SIL/PatternMatch.h index ba05b4ad80629..ef75ce6fa1237 100644 --- a/include/swift/SIL/PatternMatch.h +++ b/include/swift/SIL/PatternMatch.h @@ -649,7 +649,7 @@ using BuiltinApplyTy = typename Apply_match::Ty; #define BUILTIN_CAST_OR_BITCAST_OPERATION(Id, Name, Attrs) \ BUILTIN_UNARY_OP_MATCH_WITH_ARG_MATCHER(Id, Id) -#define BUILTIN_BINARY_OPERATION(Id, Name, Attrs, Overload) \ +#define BUILTIN_BINARY_OPERATION_ALL(Id, Name, Attrs, Overload) \ BUILTIN_BINARY_OP_MATCH_WITH_ARG_MATCHER(Id, Id) #define BUILTIN_BINARY_PREDICATE(Id, Name, Attrs, Overload) \ diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index 3866fbdc4eb1c..99457c52d0c8e 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -1181,6 +1181,15 @@ static ValueDecl *getOnceOperation(ASTContext &Context, } } +static ValueDecl *getPolymorphicBinaryOperation(ASTContext &ctx, + Identifier id) { + BuiltinGenericSignatureBuilder builder(ctx); + builder.addParameter(makeGenericParam()); + builder.addParameter(makeGenericParam()); + builder.setResult(makeGenericParam()); + return builder.build(id); +} + /// An array of the overloaded builtin kinds. static const OverloadedBuiltinKind OverloadedBuiltinKinds[] = { OverloadedBuiltinKind::None, @@ -1191,8 +1200,10 @@ static const OverloadedBuiltinKind OverloadedBuiltinKinds[] = { OverloadedBuiltinKind::Special, #define BUILTIN_CAST_OR_BITCAST_OPERATION(id, attrs, name) \ OverloadedBuiltinKind::Special, -#define BUILTIN_BINARY_OPERATION(id, name, attrs, overload) \ - OverloadedBuiltinKind::overload, +#define BUILTIN_BINARY_OPERATION_OVERLOADED_STATIC(id, name, attrs, overload) \ + OverloadedBuiltinKind::overload, +#define BUILTIN_BINARY_OPERATION_POLYMORPHIC(id, name, attrs) \ + OverloadedBuiltinKind::Special, #define BUILTIN_BINARY_OPERATION_WITH_OVERFLOW(id, name, _, attrs, overload) \ OverloadedBuiltinKind::overload, #define BUILTIN_BINARY_PREDICATE(id, name, attrs, overload) \ @@ -1777,11 +1788,22 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { return getEndUnpairedAccessOperation(Context, Id); #define BUILTIN(id, name, Attrs) -#define BUILTIN_BINARY_OPERATION(id, name, attrs, overload) case BuiltinValueKind::id: +#define BUILTIN_BINARY_OPERATION(id, name, attrs) +#define BUILTIN_BINARY_OPERATION_OVERLOADED_STATIC(id, name, attrs, overload) \ + case BuiltinValueKind::id: #include "swift/AST/Builtins.def" if (Types.size() != 1) return nullptr; return getBinaryOperation(Id, Types[0]); +#define BUILTIN(id, name, attrs) +#define BUILTIN_BINARY_OPERATION(id, name, attrs) +#define BUILTIN_BINARY_OPERATION_POLYMORPHIC(id, name, attrs) \ + case BuiltinValueKind::id: +#include "swift/AST/Builtins.def" + if (!Types.empty()) + return nullptr; + return getPolymorphicBinaryOperation(Context, Id); + #define BUILTIN(id, name, Attrs) #define BUILTIN_BINARY_OPERATION_WITH_OVERFLOW(id, name, _, attrs, overload) case BuiltinValueKind::id: #include "swift/AST/Builtins.def" @@ -2034,6 +2056,21 @@ StringRef swift::getBuiltinName(BuiltinValueKind ID) { llvm_unreachable("bad BuiltinValueKind"); } +bool swift::isPolymorphicBuiltin(BuiltinValueKind id) { + switch (id) { + case BuiltinValueKind::None: + llvm_unreachable("no builtin kind"); +#define BUILTIN(Id, Name, Attrs) \ + case BuiltinValueKind::Id: \ + return false; +#define BUILTIN_BINARY_OPERATION_POLYMORPHIC(Id, Name, Attrs) \ + case BuiltinValueKind::Id: \ + return true; +#include "swift/AST/Builtins.def" + } + llvm_unreachable("bad BuiltinValueKind"); +} + BuiltinTypeKind BuiltinType::getBuiltinTypeKind() const { // If we do not have a vector or an integer our job is easy. return BuiltinTypeKind(std::underlying_type::type(getKind())); diff --git a/lib/IRGen/GenBuiltin.cpp b/lib/IRGen/GenBuiltin.cpp index 6b91da3604bdf..e3d3489eb5a36 100644 --- a/lib/IRGen/GenBuiltin.cpp +++ b/lib/IRGen/GenBuiltin.cpp @@ -305,14 +305,18 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin, if (Builtin.ID == BuiltinValueKind::id) \ return emitCastOrBitCastBuiltin(IGF, resultType, out, args, \ BuiltinValueKind::id); - -#define BUILTIN_BINARY_OPERATION(id, name, attrs, overload) \ - if (Builtin.ID == BuiltinValueKind::id) { \ - llvm::Value *lhs = args.claimNext(); \ - llvm::Value *rhs = args.claimNext(); \ - llvm::Value *v = IGF.Builder.Create##id(lhs, rhs); \ - return out.add(v); \ + +#define BUILTIN_BINARY_OPERATION_OVERLOADED_STATIC(id, name, attrs, overload) \ + if (Builtin.ID == BuiltinValueKind::id) { \ + llvm::Value *lhs = args.claimNext(); \ + llvm::Value *rhs = args.claimNext(); \ + llvm::Value *v = IGF.Builder.Create##id(lhs, rhs); \ + return out.add(v); \ } +#define BUILTIN_BINARY_OPERATION_POLYMORPHIC(id, name, attrs) \ + assert(Builtin.ID != BuiltinValueKind::id && \ + "This builtin should never be seen by IRGen. It is invalid in " \ + "Lowered sil"); #define BUILTIN_RUNTIME_CALL(id, name, attrs) \ if (Builtin.ID == BuiltinValueKind::id) { \ diff --git a/lib/SIL/OperandOwnership.cpp b/lib/SIL/OperandOwnership.cpp index 62f729b7b8459..face71e5f2177 100644 --- a/lib/SIL/OperandOwnership.cpp +++ b/lib/SIL/OperandOwnership.cpp @@ -917,10 +917,13 @@ ANY_OWNERSHIP_BUILTIN(ErrorInMain) ANY_OWNERSHIP_BUILTIN(UnexpectedError) ANY_OWNERSHIP_BUILTIN(WillThrow) ANY_OWNERSHIP_BUILTIN(AShr) +ANY_OWNERSHIP_BUILTIN(GenericAShr) ANY_OWNERSHIP_BUILTIN(Add) +ANY_OWNERSHIP_BUILTIN(GenericAdd) ANY_OWNERSHIP_BUILTIN(Alignof) ANY_OWNERSHIP_BUILTIN(AllocRaw) ANY_OWNERSHIP_BUILTIN(And) +ANY_OWNERSHIP_BUILTIN(GenericAnd) ANY_OWNERSHIP_BUILTIN(AssertConf) ANY_OWNERSHIP_BUILTIN(AssignCopyArrayNoAlias) ANY_OWNERSHIP_BUILTIN(AssignCopyArrayFrontToBack) @@ -940,9 +943,12 @@ ANY_OWNERSHIP_BUILTIN(CopyArray) ANY_OWNERSHIP_BUILTIN(DeallocRaw) ANY_OWNERSHIP_BUILTIN(DestroyArray) ANY_OWNERSHIP_BUILTIN(ExactSDiv) +ANY_OWNERSHIP_BUILTIN(GenericExactSDiv) ANY_OWNERSHIP_BUILTIN(ExactUDiv) +ANY_OWNERSHIP_BUILTIN(GenericExactUDiv) ANY_OWNERSHIP_BUILTIN(ExtractElement) ANY_OWNERSHIP_BUILTIN(FAdd) +ANY_OWNERSHIP_BUILTIN(GenericFAdd) ANY_OWNERSHIP_BUILTIN(FCMP_OEQ) ANY_OWNERSHIP_BUILTIN(FCMP_OGE) ANY_OWNERSHIP_BUILTIN(FCMP_OGT) @@ -958,14 +964,18 @@ ANY_OWNERSHIP_BUILTIN(FCMP_ULT) ANY_OWNERSHIP_BUILTIN(FCMP_UNE) ANY_OWNERSHIP_BUILTIN(FCMP_UNO) ANY_OWNERSHIP_BUILTIN(FDiv) +ANY_OWNERSHIP_BUILTIN(GenericFDiv) ANY_OWNERSHIP_BUILTIN(FMul) +ANY_OWNERSHIP_BUILTIN(GenericFMul) ANY_OWNERSHIP_BUILTIN(FNeg) ANY_OWNERSHIP_BUILTIN(FPExt) ANY_OWNERSHIP_BUILTIN(FPToSI) ANY_OWNERSHIP_BUILTIN(FPToUI) ANY_OWNERSHIP_BUILTIN(FPTrunc) ANY_OWNERSHIP_BUILTIN(FRem) +ANY_OWNERSHIP_BUILTIN(GenericFRem) ANY_OWNERSHIP_BUILTIN(FSub) +ANY_OWNERSHIP_BUILTIN(GenericFSub) ANY_OWNERSHIP_BUILTIN(Fence) ANY_OWNERSHIP_BUILTIN(GetObjCTypeEncoding) ANY_OWNERSHIP_BUILTIN(ICMP_EQ) @@ -987,29 +997,36 @@ ANY_OWNERSHIP_BUILTIN(IsConcrete) ANY_OWNERSHIP_BUILTIN(IsBitwiseTakable) ANY_OWNERSHIP_BUILTIN(IsSameMetatype) ANY_OWNERSHIP_BUILTIN(LShr) +ANY_OWNERSHIP_BUILTIN(GenericLShr) ANY_OWNERSHIP_BUILTIN(Mul) +ANY_OWNERSHIP_BUILTIN(GenericMul) ANY_OWNERSHIP_BUILTIN(OnFastPath) ANY_OWNERSHIP_BUILTIN(Once) ANY_OWNERSHIP_BUILTIN(OnceWithContext) ANY_OWNERSHIP_BUILTIN(Or) +ANY_OWNERSHIP_BUILTIN(GenericOr) ANY_OWNERSHIP_BUILTIN(PtrToInt) ANY_OWNERSHIP_BUILTIN(SAddOver) ANY_OWNERSHIP_BUILTIN(SDiv) +ANY_OWNERSHIP_BUILTIN(GenericSDiv) ANY_OWNERSHIP_BUILTIN(SExt) ANY_OWNERSHIP_BUILTIN(SExtOrBitCast) ANY_OWNERSHIP_BUILTIN(SIToFP) ANY_OWNERSHIP_BUILTIN(SMulOver) ANY_OWNERSHIP_BUILTIN(SRem) +ANY_OWNERSHIP_BUILTIN(GenericSRem) ANY_OWNERSHIP_BUILTIN(SSubOver) ANY_OWNERSHIP_BUILTIN(SToSCheckedTrunc) ANY_OWNERSHIP_BUILTIN(SToUCheckedTrunc) ANY_OWNERSHIP_BUILTIN(Expect) ANY_OWNERSHIP_BUILTIN(Shl) +ANY_OWNERSHIP_BUILTIN(GenericShl) ANY_OWNERSHIP_BUILTIN(Sizeof) ANY_OWNERSHIP_BUILTIN(StaticReport) ANY_OWNERSHIP_BUILTIN(Strideof) ANY_OWNERSHIP_BUILTIN(StringObjectOr) ANY_OWNERSHIP_BUILTIN(Sub) +ANY_OWNERSHIP_BUILTIN(GenericSub) ANY_OWNERSHIP_BUILTIN(TakeArrayNoAlias) ANY_OWNERSHIP_BUILTIN(TakeArrayBackToFront) ANY_OWNERSHIP_BUILTIN(TakeArrayFrontToBack) @@ -1018,15 +1035,18 @@ ANY_OWNERSHIP_BUILTIN(TruncOrBitCast) ANY_OWNERSHIP_BUILTIN(TSanInoutAccess) ANY_OWNERSHIP_BUILTIN(UAddOver) ANY_OWNERSHIP_BUILTIN(UDiv) +ANY_OWNERSHIP_BUILTIN(GenericUDiv) ANY_OWNERSHIP_BUILTIN(UIToFP) ANY_OWNERSHIP_BUILTIN(UMulOver) ANY_OWNERSHIP_BUILTIN(URem) +ANY_OWNERSHIP_BUILTIN(GenericURem) ANY_OWNERSHIP_BUILTIN(USubOver) ANY_OWNERSHIP_BUILTIN(UToSCheckedTrunc) ANY_OWNERSHIP_BUILTIN(UToUCheckedTrunc) ANY_OWNERSHIP_BUILTIN(Unreachable) ANY_OWNERSHIP_BUILTIN(UnsafeGuaranteedEnd) ANY_OWNERSHIP_BUILTIN(Xor) +ANY_OWNERSHIP_BUILTIN(GenericXor) ANY_OWNERSHIP_BUILTIN(ZExt) ANY_OWNERSHIP_BUILTIN(ZExtOrBitCast) ANY_OWNERSHIP_BUILTIN(ZeroInitializer) diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp index b701d1b7e4226..b63fc7b9b9711 100644 --- a/lib/SIL/SILVerifier.cpp +++ b/lib/SIL/SILVerifier.cpp @@ -1640,6 +1640,10 @@ class SILVerifier : public SILVerifierBase { // actual ValueDecl. Otherwise, we have an invalid builtin. require(getBuiltinValueDecl(BI->getModule().getASTContext(), BI->getName()), "Invalid builtin name?!"); + + require(BI->getModule().getStage() != SILStage::Lowered || + !isPolymorphicBuiltin(*BI->getBuiltinKind()), + "Polymorphic builtins are illegal in lowered SIL?!"); } void checkFunctionRefBaseInst(FunctionRefBaseInst *FRI) { diff --git a/lib/SIL/ValueOwnership.cpp b/lib/SIL/ValueOwnership.cpp index 5b8530fb09c60..9fd00e0df9d8f 100644 --- a/lib/SIL/ValueOwnership.cpp +++ b/lib/SIL/ValueOwnership.cpp @@ -374,15 +374,21 @@ struct ValueOwnershipKindBuiltinVisitor // UnsafeGuaranteedEnd. This provides the guarantee that we want. CONSTANT_OWNERSHIP_BUILTIN(Owned, UnsafeGuaranteed) CONSTANT_OWNERSHIP_BUILTIN(Any, AShr) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericAShr) CONSTANT_OWNERSHIP_BUILTIN(Any, Add) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericAdd) CONSTANT_OWNERSHIP_BUILTIN(Any, And) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericAnd) CONSTANT_OWNERSHIP_BUILTIN(Any, AssumeNonNegative) CONSTANT_OWNERSHIP_BUILTIN(Any, AssumeTrue) CONSTANT_OWNERSHIP_BUILTIN(Any, BitCast) CONSTANT_OWNERSHIP_BUILTIN(Any, CondFailMessage) CONSTANT_OWNERSHIP_BUILTIN(Any, ExactSDiv) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericExactSDiv) CONSTANT_OWNERSHIP_BUILTIN(Any, ExactUDiv) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericExactUDiv) CONSTANT_OWNERSHIP_BUILTIN(Any, FAdd) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericFAdd) CONSTANT_OWNERSHIP_BUILTIN(Any, FCMP_OEQ) CONSTANT_OWNERSHIP_BUILTIN(Any, FCMP_OGE) CONSTANT_OWNERSHIP_BUILTIN(Any, FCMP_OGT) @@ -396,14 +402,18 @@ CONSTANT_OWNERSHIP_BUILTIN(Any, FCMP_ULE) CONSTANT_OWNERSHIP_BUILTIN(Any, FCMP_ULT) CONSTANT_OWNERSHIP_BUILTIN(Any, FCMP_UNE) CONSTANT_OWNERSHIP_BUILTIN(Any, FDiv) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericFDiv) CONSTANT_OWNERSHIP_BUILTIN(Any, FMul) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericFMul) CONSTANT_OWNERSHIP_BUILTIN(Any, FNeg) CONSTANT_OWNERSHIP_BUILTIN(Any, FPExt) CONSTANT_OWNERSHIP_BUILTIN(Any, FPToSI) CONSTANT_OWNERSHIP_BUILTIN(Any, FPToUI) CONSTANT_OWNERSHIP_BUILTIN(Any, FPTrunc) CONSTANT_OWNERSHIP_BUILTIN(Any, FRem) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericFRem) CONSTANT_OWNERSHIP_BUILTIN(Any, FSub) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericFSub) CONSTANT_OWNERSHIP_BUILTIN(Any, ICMP_EQ) CONSTANT_OWNERSHIP_BUILTIN(Any, ICMP_NE) CONSTANT_OWNERSHIP_BUILTIN(Any, ICMP_SGE) @@ -416,29 +426,39 @@ CONSTANT_OWNERSHIP_BUILTIN(Any, ICMP_ULE) CONSTANT_OWNERSHIP_BUILTIN(Any, ICMP_ULT) CONSTANT_OWNERSHIP_BUILTIN(Any, IntToPtr) CONSTANT_OWNERSHIP_BUILTIN(Any, LShr) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericLShr) CONSTANT_OWNERSHIP_BUILTIN(Any, Mul) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericMul) CONSTANT_OWNERSHIP_BUILTIN(Any, Or) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericOr) CONSTANT_OWNERSHIP_BUILTIN(Any, PtrToInt) CONSTANT_OWNERSHIP_BUILTIN(Any, SAddOver) CONSTANT_OWNERSHIP_BUILTIN(Any, SDiv) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericSDiv) CONSTANT_OWNERSHIP_BUILTIN(Any, SExt) CONSTANT_OWNERSHIP_BUILTIN(Any, SExtOrBitCast) CONSTANT_OWNERSHIP_BUILTIN(Any, SIToFP) CONSTANT_OWNERSHIP_BUILTIN(Any, SMulOver) CONSTANT_OWNERSHIP_BUILTIN(Any, SRem) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericSRem) CONSTANT_OWNERSHIP_BUILTIN(Any, SSubOver) CONSTANT_OWNERSHIP_BUILTIN(Any, Expect) CONSTANT_OWNERSHIP_BUILTIN(Any, Shl) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericShl) CONSTANT_OWNERSHIP_BUILTIN(Any, Sub) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericSub) CONSTANT_OWNERSHIP_BUILTIN(Any, Trunc) CONSTANT_OWNERSHIP_BUILTIN(Any, TruncOrBitCast) CONSTANT_OWNERSHIP_BUILTIN(Any, UAddOver) CONSTANT_OWNERSHIP_BUILTIN(Any, UDiv) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericUDiv) CONSTANT_OWNERSHIP_BUILTIN(Any, UIToFP) CONSTANT_OWNERSHIP_BUILTIN(Any, UMulOver) CONSTANT_OWNERSHIP_BUILTIN(Any, URem) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericURem) CONSTANT_OWNERSHIP_BUILTIN(Any, USubOver) CONSTANT_OWNERSHIP_BUILTIN(Any, Xor) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericXor) CONSTANT_OWNERSHIP_BUILTIN(Any, ZExt) CONSTANT_OWNERSHIP_BUILTIN(Any, ZExtOrBitCast) CONSTANT_OWNERSHIP_BUILTIN(Any, FCMP_ORD) diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index 11a9c69039512..f959d492c5e01 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -4040,6 +4040,26 @@ CallEmission::applySpecializedEmitter(SpecializedEmitter &specializedEmitter, return firstLevelResult; } + Optional resultPlan; + Optional argScope; + Optional calleeTypeInfo; + SILLocation loc = uncurriedSites[0].Loc; + SILFunctionConventions substConv(substFnType, SGF.SGM.M); + + // If we have a named builtin and have an indirect out parameter, compute a + // result plan/arg scope before we prepare arguments. + if (!specializedEmitter.isLateEmitter() && + substConv.hasIndirectSILResults()) { + calleeTypeInfo.emplace(callee.getTypeInfo(SGF, false /*isCurried*/)); + + calleeTypeInfo->origResultType = origFormalType.getFunctionResultType(); + calleeTypeInfo->substResultType = callee.getSubstFormalType().getResult(); + + resultPlan.emplace(ResultPlanBuilder::computeResultPlan( + SGF, *calleeTypeInfo, loc, uncurriedContext)); + argScope.emplace(SGF, loc); + } + // Emit the arguments. SmallVector uncurriedArgs; Optional uncurriedLoc; @@ -4049,36 +4069,64 @@ CallEmission::applySpecializedEmitter(SpecializedEmitter &specializedEmitter, firstLevelResult.foreignSelf, uncurriedArgs, uncurriedLoc, formalApplyType); - // If we have a late emitter, just delegate to that emitter and return. + // If we have a late emitter, now that we have emitted our arguments, call the + // emitter. if (specializedEmitter.isLateEmitter()) { auto emitter = specializedEmitter.getLateEmitter(); - ManagedValue mv = emitter(SGF, *uncurriedLoc, - callee.getSubstitutions(), + ManagedValue mv = emitter(SGF, loc, callee.getSubstitutions(), uncurriedArgs, uncurriedContext); - firstLevelResult.value = - RValue(SGF, *uncurriedLoc, formalApplyType.getResult(), mv); + firstLevelResult.value = RValue(SGF, loc, formalApplyType.getResult(), mv); return firstLevelResult; } - // Named Builtins. + // Otherwise, we must have a named builtin. assert(specializedEmitter.isNamedBuiltin()); auto builtinName = specializedEmitter.getBuiltinName(); - SmallVector consumedArgs; + + // Prepare our raw args. + SmallVector rawArgs; + + // First get the indirect result addrs and add them to rawArgs. We want to be + // able to handle them specially later as well, so we keep them in two arrays. + if (resultPlan.hasValue()) + (*resultPlan)->gatherIndirectResultAddrs(SGF, loc, rawArgs); + + // Then add all arguments to our array, copying them if they are not at +1 + // yet. for (auto arg : uncurriedArgs) { // Named builtins are by default assumed to take all arguments at +1 i.e., // as Owned or Trivial. Named builtins that don't follow this convention // must use a specialized emitter. - auto maybePlusOne = arg.ensurePlusOne(SGF, uncurriedLoc.getValue()); - consumedArgs.push_back(maybePlusOne.forward(SGF)); + auto maybePlusOne = arg.ensurePlusOne(SGF, loc); + rawArgs.push_back(maybePlusOne.forward(SGF)); + } + + SILValue rawResult = + SGF.B.createBuiltin(loc, builtinName, substConv.getSILResultType(), + callee.getSubstitutions(), rawArgs); + + if (argScope.hasValue()) + std::move(argScope)->pop(); + + // If we have a direct result, it will consist of a single value even if + // formally we have multiple values. We could handle this better today by + // using multiple return values instead of a tuple. + SmallVector directResultsArray; + if (!substConv.hasIndirectSILResults()) { + directResultsArray.push_back(SGF.emitManagedRValueWithCleanup(rawResult)); + } + + ArrayRef directResultsFinal(directResultsArray); + + // Then finish our value. + if (resultPlan.hasValue()) { + firstLevelResult.value = + std::move(*resultPlan) + ->finish(SGF, loc, formalApplyType.getResult(), directResultsFinal); + } else { + firstLevelResult.value = RValue( + SGF, *uncurriedLoc, formalApplyType.getResult(), directResultsFinal[0]); } - SILFunctionConventions substConv(substFnType, SGF.SGM.M); - auto resultVal = SGF.B.createBuiltin(uncurriedLoc.getValue(), builtinName, - substConv.getSILResultType(), - callee.getSubstitutions(), - consumedArgs); - firstLevelResult.value = - RValue(SGF, *uncurriedLoc, formalApplyType.getResult(), - SGF.emitManagedRValueWithCleanup(resultVal)); return firstLevelResult; } diff --git a/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp b/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp index 05c33e6c05d0e..f28a9c32ff6cf 100644 --- a/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp +++ b/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp @@ -89,8 +89,7 @@ static bool isBarrier(SILInstruction *inst) { #define BUILTIN_CAST_OPERATION(Id, Name, Attrs) BUILTIN_NO_BARRIER(Id) #define BUILTIN_CAST_OR_BITCAST_OPERATION(Id, Name, Attrs) \ BUILTIN_NO_BARRIER(Id) -#define BUILTIN_BINARY_OPERATION(Id, Name, Attrs, Overload) \ - BUILTIN_NO_BARRIER(Id) +#define BUILTIN_BINARY_OPERATION(Id, Name, Attrs) BUILTIN_NO_BARRIER(Id) #define BUILTIN_BINARY_OPERATION_WITH_OVERFLOW(Id, Name, UncheckedID, Attrs, \ Overload) \ BUILTIN_NO_BARRIER(Id) @@ -105,6 +104,11 @@ static bool isBarrier(SILInstruction *inst) { case BuiltinValueKind::Id: \ return true; // A runtime call could be anything. +#define BUILTIN_SANITIZER_OPERATION(Id, Name, Attrs) BUILTIN_NO_BARRIER(Id) +#define BUILTIN_TYPE_CHECKER_OPERATION(Id, Name) BUILTIN_NO_BARRIER(Id) +#define BUILTIN_TYPE_TRAIT_OPERATION(Id, Name) BUILTIN_NO_BARRIER(Id) +#include "swift/AST/Builtins.def" + // Handle BUILTIN_MISC_OPERATIONs individually. case BuiltinValueKind::Sizeof: case BuiltinValueKind::Strideof: @@ -158,12 +162,6 @@ static bool isBarrier(SILInstruction *inst) { case BuiltinValueKind::UnsafeGuaranteed: case BuiltinValueKind::UnsafeGuaranteedEnd: return true; - -#define BUILTIN_SANITIZER_OPERATION(Id, Name, Attrs) BUILTIN_NO_BARRIER(Id) -#define BUILTIN_TYPE_CHECKER_OPERATION(Id, Name) BUILTIN_NO_BARRIER(Id) -#define BUILTIN_TYPE_TRAIT_OPERATION(Id, Name) BUILTIN_NO_BARRIER(Id) - -#include "swift/AST/Builtins.def" } } return false; diff --git a/lib/SILOptimizer/Utils/ConstantFolding.cpp b/lib/SILOptimizer/Utils/ConstantFolding.cpp index aca46e3e52e9c..50d846ec13937 100644 --- a/lib/SILOptimizer/Utils/ConstantFolding.cpp +++ b/lib/SILOptimizer/Utils/ConstantFolding.cpp @@ -1201,9 +1201,8 @@ static SILValue constantFoldBuiltin(BuiltinInst *BI, #include "swift/AST/Builtins.def" return constantFoldBinaryWithOverflow(BI, Builtin.ID, ResultsInError); -#define BUILTIN(id, name, Attrs) -#define BUILTIN_BINARY_OPERATION(id, name, attrs, overload) \ -case BuiltinValueKind::id: +#define BUILTIN(id, name, attrs) +#define BUILTIN_BINARY_OPERATION(id, name, attrs) case BuiltinValueKind::id: #include "swift/AST/Builtins.def" return constantFoldBinary(BI, Builtin.ID, ResultsInError); diff --git a/test/SIL/polymorphic_builtins.sil b/test/SIL/polymorphic_builtins.sil new file mode 100644 index 0000000000000..f4fbcceac235a --- /dev/null +++ b/test/SIL/polymorphic_builtins.sil @@ -0,0 +1,135 @@ +// RUN: %target-sil-opt %s -o - | %target-sil-opt + +// Just make sure we can parse polymorphic builtins, recognize them, round trip +// them. + +sil_stage raw + +import Builtin + +sil @generic_add_test : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +bb0(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32): + %2 = builtin "generic_add"(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 + return %2 : $Builtin.Vec4xInt32 +} + +sil @generic_add_indirect_param_test : $@convention(thin) (@in Builtin.Vec4xInt32, @in Builtin.Vec4xInt32) -> @out Builtin.Vec4xInt32 { +bb0(%0 : $*Builtin.Vec4xInt32, %1 : $*Builtin.Vec4xInt32, %2 : $*Builtin.Vec4xInt32): + %3 = builtin "generic_add"(%0 : $*Builtin.Vec4xInt32, %1 : $*Builtin.Vec4xInt32, %2 : $*Builtin.Vec4xInt32) : $() + %9999 = tuple() + return %9999 : $() +} + +sil @generic_fadd_test : $@convention(thin) (Builtin.Vec4xFPIEEE32, Builtin.Vec4xFPIEEE32) -> Builtin.Vec4xFPIEEE32 { +bb0(%0 : $Builtin.Vec4xFPIEEE32, %1 : $Builtin.Vec4xFPIEEE32): + %2 = builtin "generic_fadd"(%0 : $Builtin.Vec4xFPIEEE32, %1 : $Builtin.Vec4xFPIEEE32) : $Builtin.Vec4xFPIEEE32 + return %2 : $Builtin.Vec4xFPIEEE32 +} + +sil @generic_and_test : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +bb0(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32): + %2 = builtin "generic_and"(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 + return %2 : $Builtin.Vec4xInt32 +} + +sil @generic_ashr_test : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +bb0(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32): + %2 = builtin "generic_ashr"(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 + return %2 : $Builtin.Vec4xInt32 +} + +sil @generic_lshr_test : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +bb0(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32): + %2 = builtin "generic_lshr"(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 + return %2 : $Builtin.Vec4xInt32 +} + +sil @generic_or_test : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +bb0(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32): + %2 = builtin "generic_or"(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 + return %2 : $Builtin.Vec4xInt32 +} + +sil @generic_fdiv_test : $@convention(thin) (Builtin.Vec4xFPIEEE32, Builtin.Vec4xFPIEEE32) -> Builtin.Vec4xFPIEEE32 { +bb0(%0 : $Builtin.Vec4xFPIEEE32, %1 : $Builtin.Vec4xFPIEEE32): + %2 = builtin "generic_fdiv"(%0 : $Builtin.Vec4xFPIEEE32, %1 : $Builtin.Vec4xFPIEEE32) : $Builtin.Vec4xFPIEEE32 + return %2 : $Builtin.Vec4xFPIEEE32 +} + +sil @generic_mul_test : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +bb0(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32): + %2 = builtin "generic_mul"(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 + return %2 : $Builtin.Vec4xInt32 +} + +sil @generic_fmul_test : $@convention(thin) (Builtin.Vec4xFPIEEE32, Builtin.Vec4xFPIEEE32) -> Builtin.Vec4xFPIEEE32 { +bb0(%0 : $Builtin.Vec4xFPIEEE32, %1 : $Builtin.Vec4xFPIEEE32): + %2 = builtin "generic_fmul"(%0 : $Builtin.Vec4xFPIEEE32, %1 : $Builtin.Vec4xFPIEEE32) : $Builtin.Vec4xFPIEEE32 + return %2 : $Builtin.Vec4xFPIEEE32 +} + +sil @generic_sdiv_test : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +bb0(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32): + %2 = builtin "generic_sdiv"(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 + return %2 : $Builtin.Vec4xInt32 +} + +sil @generic_sdiv_exact_test : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +bb0(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32): + %2 = builtin "generic_sdiv_exact"(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 + return %2 : $Builtin.Vec4xInt32 +} + +sil @generic_shl_test : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +bb0(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32): + %2 = builtin "generic_shl"(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 + return %2 : $Builtin.Vec4xInt32 +} + +sil @generic_srem_test : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +bb0(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32): + %2 = builtin "generic_srem"(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 + return %2 : $Builtin.Vec4xInt32 +} + +sil @generic_sub_test : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +bb0(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32): + %2 = builtin "generic_sub"(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 + return %2 : $Builtin.Vec4xInt32 +} + +sil @generic_udiv_test : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +bb0(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32): + %2 = builtin "generic_udiv"(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 + return %2 : $Builtin.Vec4xInt32 +} + +sil @generic_udiv_exact_test : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +bb0(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32): + %2 = builtin "generic_udiv_exact"(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 + return %2 : $Builtin.Vec4xInt32 +} + +sil @generic_xor_test : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +bb0(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32): + %2 = builtin "generic_xor"(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 + return %2 : $Builtin.Vec4xInt32 +} + +sil @generic_fsub_test : $@convention(thin) (Builtin.Vec4xFPIEEE32, Builtin.Vec4xFPIEEE32) -> Builtin.Vec4xFPIEEE32 { +bb0(%0 : $Builtin.Vec4xFPIEEE32, %1 : $Builtin.Vec4xFPIEEE32): + %2 = builtin "generic_fsub"(%0 : $Builtin.Vec4xFPIEEE32, %1 : $Builtin.Vec4xFPIEEE32) : $Builtin.Vec4xFPIEEE32 + return %2 : $Builtin.Vec4xFPIEEE32 +} + +sil @generic_frem_test : $@convention(thin) (Builtin.Vec4xFPIEEE32, Builtin.Vec4xFPIEEE32) -> Builtin.Vec4xFPIEEE32 { +bb0(%0 : $Builtin.Vec4xFPIEEE32, %1 : $Builtin.Vec4xFPIEEE32): + %2 = builtin "generic_frem"(%0 : $Builtin.Vec4xFPIEEE32, %1 : $Builtin.Vec4xFPIEEE32) : $Builtin.Vec4xFPIEEE32 + return %2 : $Builtin.Vec4xFPIEEE32 +} + +sil @generic_urem_test : $@convention(thin) (Builtin.Int64, Builtin.Int64) -> Builtin.Int64 { +bb0(%0 : $Builtin.Int64, %1 : $Builtin.Int64): + %2 = builtin "generic_urem"(%0 : $Builtin.Int64, %1 : $Builtin.Int64) : $Builtin.Int64 + return %2 : $Builtin.Int64 +} diff --git a/test/SILGen/polymorphic_builtins.swift b/test/SILGen/polymorphic_builtins.swift new file mode 100644 index 0000000000000..ced15529b3fde --- /dev/null +++ b/test/SILGen/polymorphic_builtins.swift @@ -0,0 +1,421 @@ +// RUN: %target-swift-frontend -parse-stdlib -emit-silgen %s | %FileCheck %s + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}concreteAddTest{{.*}} : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +// CHECK: bb0([[ARG0:%.*]] : $Builtin.Vec4xInt32, [[ARG1:%.*]] : $Builtin.Vec4xInt32): +// CHECK: [[RESULT:%.*]] = builtin "generic_add"([[ARG0]] : $Builtin.Vec4xInt32, [[ARG1]] : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 +// CHECK: return [[RESULT]] +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}concreteAddTest{{.*}}' +func concreteAddTest(_ x: Builtin.Vec4xInt32, _ y: Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { + return Builtin.generic_add(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}genericAddTest{{.*}} : $@convention(thin) (@in_guaranteed T, @in_guaranteed T) -> @out T { +// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T): +// CHECK: [[STACK_SLOT_0:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG0]] to [initialization] [[STACK_SLOT_0]] +// CHECK: [[STACK_SLOT_1:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG1]] to [initialization] [[STACK_SLOT_1]] +// CHECK: builtin "generic_add"([[RESULT]] : $*T, [[STACK_SLOT_0]] : $*T, [[STACK_SLOT_1]] : $*T) : $() +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}genericAddTest{{.*}}' +func genericAddTest(_ x : T, _ y : T) -> T { + return Builtin.generic_add(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}concreteAndTest{{.*}} : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +// CHECK: bb0([[ARG0:%.*]] : $Builtin.Vec4xInt32, [[ARG1:%.*]] : $Builtin.Vec4xInt32): +// CHECK: [[RESULT:%.*]] = builtin "generic_and"([[ARG0]] : $Builtin.Vec4xInt32, [[ARG1]] : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 +// CHECK: return [[RESULT]] +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}concreteAndTest{{.*}}' +func concreteAndTest(_ x: Builtin.Vec4xInt32, _ y: Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { + return Builtin.generic_and(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}genericAndTest{{.*}} : $@convention(thin) (@in_guaranteed T, @in_guaranteed T) -> @out T { +// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T): +// CHECK: [[STACK_SLOT_0:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG0]] to [initialization] [[STACK_SLOT_0]] +// CHECK: [[STACK_SLOT_1:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG1]] to [initialization] [[STACK_SLOT_1]] +// CHECK: builtin "generic_and"([[RESULT]] : $*T, [[STACK_SLOT_0]] : $*T, [[STACK_SLOT_1]] : $*T) : $() +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}genericAndTest{{.*}}' +func genericAndTest(_ x : T, _ y : T) -> T { + return Builtin.generic_and(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}concreteAshrTest{{.*}} : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +// CHECK: bb0([[ARG0:%.*]] : $Builtin.Vec4xInt32, [[ARG1:%.*]] : $Builtin.Vec4xInt32): +// CHECK: [[RESULT:%.*]] = builtin "generic_ashr"([[ARG0]] : $Builtin.Vec4xInt32, [[ARG1]] : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 +// CHECK: return [[RESULT]] +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}concreteAshrTest{{.*}}' +func concreteAshrTest(_ x: Builtin.Vec4xInt32, _ y: Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { + return Builtin.generic_ashr(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}genericAshrTest{{.*}} : $@convention(thin) (@in_guaranteed T, @in_guaranteed T) -> @out T { +// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T): +// CHECK: [[STACK_SLOT_0:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG0]] to [initialization] [[STACK_SLOT_0]] +// CHECK: [[STACK_SLOT_1:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG1]] to [initialization] [[STACK_SLOT_1]] +// CHECK: builtin "generic_ashr"([[RESULT]] : $*T, [[STACK_SLOT_0]] : $*T, [[STACK_SLOT_1]] : $*T) : $() +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}genericAshrTest{{.*}}' +func genericAshrTest(_ x : T, _ y : T) -> T { + return Builtin.generic_ashr(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}concreteLshrTest{{.*}} : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +// CHECK: bb0([[ARG0:%.*]] : $Builtin.Vec4xInt32, [[ARG1:%.*]] : $Builtin.Vec4xInt32): +// CHECK: [[RESULT:%.*]] = builtin "generic_lshr"([[ARG0]] : $Builtin.Vec4xInt32, [[ARG1]] : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 +// CHECK: return [[RESULT]] +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}concreteLshrTest{{.*}}' +func concreteLshrTest(_ x: Builtin.Vec4xInt32, _ y: Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { + return Builtin.generic_lshr(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}genericLshrTest{{.*}} : $@convention(thin) (@in_guaranteed T, @in_guaranteed T) -> @out T { +// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T): +// CHECK: [[STACK_SLOT_0:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG0]] to [initialization] [[STACK_SLOT_0]] +// CHECK: [[STACK_SLOT_1:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG1]] to [initialization] [[STACK_SLOT_1]] +// CHECK: builtin "generic_lshr"([[RESULT]] : $*T, [[STACK_SLOT_0]] : $*T, [[STACK_SLOT_1]] : $*T) : $() +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}genericLshrTest{{.*}}' +func genericLshrTest(_ x : T, _ y : T) -> T { + return Builtin.generic_lshr(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}concreteMulTest{{.*}} : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +// CHECK: bb0([[ARG0:%.*]] : $Builtin.Vec4xInt32, [[ARG1:%.*]] : $Builtin.Vec4xInt32): +// CHECK: [[RESULT:%.*]] = builtin "generic_mul"([[ARG0]] : $Builtin.Vec4xInt32, [[ARG1]] : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 +// CHECK: return [[RESULT]] +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}concreteMulTest{{.*}}' +func concreteMulTest(_ x: Builtin.Vec4xInt32, _ y: Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { + return Builtin.generic_mul(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}genericMulTest{{.*}} : $@convention(thin) (@in_guaranteed T, @in_guaranteed T) -> @out T { +// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T): +// CHECK: [[STACK_SLOT_0:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG0]] to [initialization] [[STACK_SLOT_0]] +// CHECK: [[STACK_SLOT_1:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG1]] to [initialization] [[STACK_SLOT_1]] +// CHECK: builtin "generic_mul"([[RESULT]] : $*T, [[STACK_SLOT_0]] : $*T, [[STACK_SLOT_1]] : $*T) : $() +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}genericMulTest{{.*}}' +func genericMulTest(_ x : T, _ y : T) -> T { + return Builtin.generic_mul(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}concreteOrTest{{.*}} : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +// CHECK: bb0([[ARG0:%.*]] : $Builtin.Vec4xInt32, [[ARG1:%.*]] : $Builtin.Vec4xInt32): +// CHECK: [[RESULT:%.*]] = builtin "generic_or"([[ARG0]] : $Builtin.Vec4xInt32, [[ARG1]] : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 +// CHECK: return [[RESULT]] +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}concreteOrTest{{.*}}' +func concreteOrTest(_ x: Builtin.Vec4xInt32, _ y: Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { + return Builtin.generic_or(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}genericOrTest{{.*}} : $@convention(thin) (@in_guaranteed T, @in_guaranteed T) -> @out T { +// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T): +// CHECK: [[STACK_SLOT_0:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG0]] to [initialization] [[STACK_SLOT_0]] +// CHECK: [[STACK_SLOT_1:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG1]] to [initialization] [[STACK_SLOT_1]] +// CHECK: builtin "generic_or"([[RESULT]] : $*T, [[STACK_SLOT_0]] : $*T, [[STACK_SLOT_1]] : $*T) : $() +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}genericOrTest{{.*}}' +func genericOrTest(_ x : T, _ y : T) -> T { + return Builtin.generic_or(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}concreteSdivTest{{.*}} : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +// CHECK: bb0([[ARG0:%.*]] : $Builtin.Vec4xInt32, [[ARG1:%.*]] : $Builtin.Vec4xInt32): +// CHECK: [[RESULT:%.*]] = builtin "generic_sdiv"([[ARG0]] : $Builtin.Vec4xInt32, [[ARG1]] : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 +// CHECK: return [[RESULT]] +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}concreteSdivTest{{.*}}' +func concreteSdivTest(_ x: Builtin.Vec4xInt32, _ y: Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { + return Builtin.generic_sdiv(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}genericSdivTest{{.*}} : $@convention(thin) (@in_guaranteed T, @in_guaranteed T) -> @out T { +// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T): +// CHECK: [[STACK_SLOT_0:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG0]] to [initialization] [[STACK_SLOT_0]] +// CHECK: [[STACK_SLOT_1:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG1]] to [initialization] [[STACK_SLOT_1]] +// CHECK: builtin "generic_sdiv"([[RESULT]] : $*T, [[STACK_SLOT_0]] : $*T, [[STACK_SLOT_1]] : $*T) : $() +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}genericSdivTest{{.*}}' +func genericSdivTest(_ x : T, _ y : T) -> T { + return Builtin.generic_sdiv(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}concreteSdivExactTest{{.*}} : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +// CHECK: bb0([[ARG0:%.*]] : $Builtin.Vec4xInt32, [[ARG1:%.*]] : $Builtin.Vec4xInt32): +// CHECK: [[RESULT:%.*]] = builtin "generic_sdiv_exact"([[ARG0]] : $Builtin.Vec4xInt32, [[ARG1]] : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 +// CHECK: return [[RESULT]] +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}concreteSdivExactTest{{.*}}' +func concreteSdivExactTest(_ x: Builtin.Vec4xInt32, _ y: Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { + return Builtin.generic_sdiv_exact(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}genericSdivExactTest{{.*}} : $@convention(thin) (@in_guaranteed T, @in_guaranteed T) -> @out T { +// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T): +// CHECK: [[STACK_SLOT_0:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG0]] to [initialization] [[STACK_SLOT_0]] +// CHECK: [[STACK_SLOT_1:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG1]] to [initialization] [[STACK_SLOT_1]] +// CHECK: builtin "generic_sdiv_exact"([[RESULT]] : $*T, [[STACK_SLOT_0]] : $*T, [[STACK_SLOT_1]] : $*T) : $() +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}genericSdivExactTest{{.*}}' +func genericSdivExactTest(_ x : T, _ y : T) -> T { + return Builtin.generic_sdiv_exact(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}concreteShlTest{{.*}} : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +// CHECK: bb0([[ARG0:%.*]] : $Builtin.Vec4xInt32, [[ARG1:%.*]] : $Builtin.Vec4xInt32): +// CHECK: [[RESULT:%.*]] = builtin "generic_shl"([[ARG0]] : $Builtin.Vec4xInt32, [[ARG1]] : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 +// CHECK: return [[RESULT]] +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}concreteShlTest{{.*}}' +func concreteShlTest(_ x: Builtin.Vec4xInt32, _ y: Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { + return Builtin.generic_shl(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}genericShlTest{{.*}} : $@convention(thin) (@in_guaranteed T, @in_guaranteed T) -> @out T { +// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T): +// CHECK: [[STACK_SLOT_0:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG0]] to [initialization] [[STACK_SLOT_0]] +// CHECK: [[STACK_SLOT_1:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG1]] to [initialization] [[STACK_SLOT_1]] +// CHECK: builtin "generic_shl"([[RESULT]] : $*T, [[STACK_SLOT_0]] : $*T, [[STACK_SLOT_1]] : $*T) : $() +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}genericShlTest{{.*}}' +func genericShlTest(_ x : T, _ y : T) -> T { + return Builtin.generic_shl(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}concreteSremTest{{.*}} : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +// CHECK: bb0([[ARG0:%.*]] : $Builtin.Vec4xInt32, [[ARG1:%.*]] : $Builtin.Vec4xInt32): +// CHECK: [[RESULT:%.*]] = builtin "generic_srem"([[ARG0]] : $Builtin.Vec4xInt32, [[ARG1]] : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 +// CHECK: return [[RESULT]] +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}concreteSremTest{{.*}}' +func concreteSremTest(_ x: Builtin.Vec4xInt32, _ y: Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { + return Builtin.generic_srem(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}genericSremTest{{.*}} : $@convention(thin) (@in_guaranteed T, @in_guaranteed T) -> @out T { +// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T): +// CHECK: [[STACK_SLOT_0:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG0]] to [initialization] [[STACK_SLOT_0]] +// CHECK: [[STACK_SLOT_1:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG1]] to [initialization] [[STACK_SLOT_1]] +// CHECK: builtin "generic_srem"([[RESULT]] : $*T, [[STACK_SLOT_0]] : $*T, [[STACK_SLOT_1]] : $*T) : $() +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}genericSremTest{{.*}}' +func genericSremTest(_ x : T, _ y : T) -> T { + return Builtin.generic_srem(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}concreteSubTest{{.*}} : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +// CHECK: bb0([[ARG0:%.*]] : $Builtin.Vec4xInt32, [[ARG1:%.*]] : $Builtin.Vec4xInt32): +// CHECK: [[RESULT:%.*]] = builtin "generic_sub"([[ARG0]] : $Builtin.Vec4xInt32, [[ARG1]] : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 +// CHECK: return [[RESULT]] +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}concreteSubTest{{.*}}' +func concreteSubTest(_ x: Builtin.Vec4xInt32, _ y: Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { + return Builtin.generic_sub(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}genericSubTest{{.*}} : $@convention(thin) (@in_guaranteed T, @in_guaranteed T) -> @out T { +// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T): +// CHECK: [[STACK_SLOT_0:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG0]] to [initialization] [[STACK_SLOT_0]] +// CHECK: [[STACK_SLOT_1:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG1]] to [initialization] [[STACK_SLOT_1]] +// CHECK: builtin "generic_sub"([[RESULT]] : $*T, [[STACK_SLOT_0]] : $*T, [[STACK_SLOT_1]] : $*T) : $() +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}genericSubTest{{.*}}' +func genericSubTest(_ x : T, _ y : T) -> T { + return Builtin.generic_sub(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}concreteUdivTest{{.*}} : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +// CHECK: bb0([[ARG0:%.*]] : $Builtin.Vec4xInt32, [[ARG1:%.*]] : $Builtin.Vec4xInt32): +// CHECK: [[RESULT:%.*]] = builtin "generic_udiv"([[ARG0]] : $Builtin.Vec4xInt32, [[ARG1]] : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 +// CHECK: return [[RESULT]] +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}concreteUdivTest{{.*}}' +func concreteUdivTest(_ x: Builtin.Vec4xInt32, _ y: Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { + return Builtin.generic_udiv(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}genericUdivTest{{.*}} : $@convention(thin) (@in_guaranteed T, @in_guaranteed T) -> @out T { +// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T): +// CHECK: [[STACK_SLOT_0:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG0]] to [initialization] [[STACK_SLOT_0]] +// CHECK: [[STACK_SLOT_1:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG1]] to [initialization] [[STACK_SLOT_1]] +// CHECK: builtin "generic_udiv"([[RESULT]] : $*T, [[STACK_SLOT_0]] : $*T, [[STACK_SLOT_1]] : $*T) : $() +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}genericUdivTest{{.*}}' +func genericUdivTest(_ x : T, _ y : T) -> T { + return Builtin.generic_udiv(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}concreteUdivExactTest{{.*}} : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +// CHECK: bb0([[ARG0:%.*]] : $Builtin.Vec4xInt32, [[ARG1:%.*]] : $Builtin.Vec4xInt32): +// CHECK: [[RESULT:%.*]] = builtin "generic_udiv_exact"([[ARG0]] : $Builtin.Vec4xInt32, [[ARG1]] : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 +// CHECK: return [[RESULT]] +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}concreteUdivExactTest{{.*}}' +func concreteUdivExactTest(_ x: Builtin.Vec4xInt32, _ y: Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { + return Builtin.generic_udiv_exact(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}genericUdivExactTest{{.*}} : $@convention(thin) (@in_guaranteed T, @in_guaranteed T) -> @out T { +// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T): +// CHECK: [[STACK_SLOT_0:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG0]] to [initialization] [[STACK_SLOT_0]] +// CHECK: [[STACK_SLOT_1:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG1]] to [initialization] [[STACK_SLOT_1]] +// CHECK: builtin "generic_udiv_exact"([[RESULT]] : $*T, [[STACK_SLOT_0]] : $*T, [[STACK_SLOT_1]] : $*T) : $() +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}genericUdivExactTest{{.*}}' +func genericUdivExactTest(_ x : T, _ y : T) -> T { + return Builtin.generic_udiv_exact(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}concreteXorTest{{.*}} : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +// CHECK: bb0([[ARG0:%.*]] : $Builtin.Vec4xInt32, [[ARG1:%.*]] : $Builtin.Vec4xInt32): +// CHECK: [[RESULT:%.*]] = builtin "generic_xor"([[ARG0]] : $Builtin.Vec4xInt32, [[ARG1]] : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 +// CHECK: return [[RESULT]] +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}concreteXorTest{{.*}}' +func concreteXorTest(_ x: Builtin.Vec4xInt32, _ y: Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { + return Builtin.generic_xor(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}genericXorTest{{.*}} : $@convention(thin) (@in_guaranteed T, @in_guaranteed T) -> @out T { +// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T): +// CHECK: [[STACK_SLOT_0:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG0]] to [initialization] [[STACK_SLOT_0]] +// CHECK: [[STACK_SLOT_1:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG1]] to [initialization] [[STACK_SLOT_1]] +// CHECK: builtin "generic_xor"([[RESULT]] : $*T, [[STACK_SLOT_0]] : $*T, [[STACK_SLOT_1]] : $*T) : $() +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}genericXorTest{{.*}}' +func genericXorTest(_ x : T, _ y : T) -> T { + return Builtin.generic_xor(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}concreteFaddTest{{.*}} : $@convention(thin) (Builtin.Vec4xFPIEEE32, Builtin.Vec4xFPIEEE32) -> Builtin.Vec4xFPIEEE32 { +// CHECK: bb0([[ARG0:%.*]] : $Builtin.Vec4xFPIEEE32, [[ARG1:%.*]] : $Builtin.Vec4xFPIEEE32): +// CHECK: [[RESULT:%.*]] = builtin "generic_fadd"([[ARG0]] : $Builtin.Vec4xFPIEEE32, [[ARG1]] : $Builtin.Vec4xFPIEEE32) : $Builtin.Vec4xFPIEEE32 +// CHECK: return [[RESULT]] +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}concreteFaddTest{{.*}}' +func concreteFaddTest(_ x: Builtin.Vec4xFPIEEE32, _ y: Builtin.Vec4xFPIEEE32) -> Builtin.Vec4xFPIEEE32 { + return Builtin.generic_fadd(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}genericFaddTest{{.*}} : $@convention(thin) (@in_guaranteed T, @in_guaranteed T) -> @out T { +// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T): +// CHECK: [[STACK_SLOT_0:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG0]] to [initialization] [[STACK_SLOT_0]] +// CHECK: [[STACK_SLOT_1:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG1]] to [initialization] [[STACK_SLOT_1]] +// CHECK: builtin "generic_fadd"([[RESULT]] : $*T, [[STACK_SLOT_0]] : $*T, [[STACK_SLOT_1]] : $*T) : $() +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}genericFaddTest{{.*}}' +func genericFaddTest(_ x : T, _ y : T) -> T { + return Builtin.generic_fadd(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}concreteFdivTest{{.*}} : $@convention(thin) (Builtin.Vec4xFPIEEE32, Builtin.Vec4xFPIEEE32) -> Builtin.Vec4xFPIEEE32 { +// CHECK: bb0([[ARG0:%.*]] : $Builtin.Vec4xFPIEEE32, [[ARG1:%.*]] : $Builtin.Vec4xFPIEEE32): +// CHECK: [[RESULT:%.*]] = builtin "generic_fdiv"([[ARG0]] : $Builtin.Vec4xFPIEEE32, [[ARG1]] : $Builtin.Vec4xFPIEEE32) : $Builtin.Vec4xFPIEEE32 +// CHECK: return [[RESULT]] +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}concreteFdivTest{{.*}}' +func concreteFdivTest(_ x: Builtin.Vec4xFPIEEE32, _ y: Builtin.Vec4xFPIEEE32) -> Builtin.Vec4xFPIEEE32 { + return Builtin.generic_fdiv(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}genericFdivTest{{.*}} : $@convention(thin) (@in_guaranteed T, @in_guaranteed T) -> @out T { +// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T): +// CHECK: [[STACK_SLOT_0:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG0]] to [initialization] [[STACK_SLOT_0]] +// CHECK: [[STACK_SLOT_1:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG1]] to [initialization] [[STACK_SLOT_1]] +// CHECK: builtin "generic_fdiv"([[RESULT]] : $*T, [[STACK_SLOT_0]] : $*T, [[STACK_SLOT_1]] : $*T) : $() +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}genericFdivTest{{.*}}' +func genericFdivTest(_ x : T, _ y : T) -> T { + return Builtin.generic_fdiv(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}concreteFmulTest{{.*}} : $@convention(thin) (Builtin.Vec4xFPIEEE32, Builtin.Vec4xFPIEEE32) -> Builtin.Vec4xFPIEEE32 { +// CHECK: bb0([[ARG0:%.*]] : $Builtin.Vec4xFPIEEE32, [[ARG1:%.*]] : $Builtin.Vec4xFPIEEE32): +// CHECK: [[RESULT:%.*]] = builtin "generic_fmul"([[ARG0]] : $Builtin.Vec4xFPIEEE32, [[ARG1]] : $Builtin.Vec4xFPIEEE32) : $Builtin.Vec4xFPIEEE32 +// CHECK: return [[RESULT]] +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}concreteFmulTest{{.*}}' +func concreteFmulTest(_ x: Builtin.Vec4xFPIEEE32, _ y: Builtin.Vec4xFPIEEE32) -> Builtin.Vec4xFPIEEE32 { + return Builtin.generic_fmul(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}genericFmulTest{{.*}} : $@convention(thin) (@in_guaranteed T, @in_guaranteed T) -> @out T { +// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T): +// CHECK: [[STACK_SLOT_0:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG0]] to [initialization] [[STACK_SLOT_0]] +// CHECK: [[STACK_SLOT_1:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG1]] to [initialization] [[STACK_SLOT_1]] +// CHECK: builtin "generic_fmul"([[RESULT]] : $*T, [[STACK_SLOT_0]] : $*T, [[STACK_SLOT_1]] : $*T) : $() +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}genericFmulTest{{.*}}' +func genericFmulTest(_ x : T, _ y : T) -> T { + return Builtin.generic_fmul(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}concreteFremTest{{.*}} : $@convention(thin) (Builtin.Vec4xFPIEEE32, Builtin.Vec4xFPIEEE32) -> Builtin.Vec4xFPIEEE32 { +// CHECK: bb0([[ARG0:%.*]] : $Builtin.Vec4xFPIEEE32, [[ARG1:%.*]] : $Builtin.Vec4xFPIEEE32): +// CHECK: [[RESULT:%.*]] = builtin "generic_frem"([[ARG0]] : $Builtin.Vec4xFPIEEE32, [[ARG1]] : $Builtin.Vec4xFPIEEE32) : $Builtin.Vec4xFPIEEE32 +// CHECK: return [[RESULT]] +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}concreteFremTest{{.*}}' +func concreteFremTest(_ x: Builtin.Vec4xFPIEEE32, _ y: Builtin.Vec4xFPIEEE32) -> Builtin.Vec4xFPIEEE32 { + return Builtin.generic_frem(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}genericFremTest{{.*}} : $@convention(thin) (@in_guaranteed T, @in_guaranteed T) -> @out T { +// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T): +// CHECK: [[STACK_SLOT_0:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG0]] to [initialization] [[STACK_SLOT_0]] +// CHECK: [[STACK_SLOT_1:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG1]] to [initialization] [[STACK_SLOT_1]] +// CHECK: builtin "generic_frem"([[RESULT]] : $*T, [[STACK_SLOT_0]] : $*T, [[STACK_SLOT_1]] : $*T) : $() +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}genericFremTest{{.*}}' +func genericFremTest(_ x : T, _ y : T) -> T { + return Builtin.generic_frem(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}concreteFsubTest{{.*}} : $@convention(thin) (Builtin.Vec4xFPIEEE32, Builtin.Vec4xFPIEEE32) -> Builtin.Vec4xFPIEEE32 { +// CHECK: bb0([[ARG0:%.*]] : $Builtin.Vec4xFPIEEE32, [[ARG1:%.*]] : $Builtin.Vec4xFPIEEE32): +// CHECK: [[RESULT:%.*]] = builtin "generic_fsub"([[ARG0]] : $Builtin.Vec4xFPIEEE32, [[ARG1]] : $Builtin.Vec4xFPIEEE32) : $Builtin.Vec4xFPIEEE32 +// CHECK: return [[RESULT]] +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}concreteFsubTest{{.*}}' +func concreteFsubTest(_ x: Builtin.Vec4xFPIEEE32, _ y: Builtin.Vec4xFPIEEE32) -> Builtin.Vec4xFPIEEE32 { + return Builtin.generic_fsub(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}genericFsubTest{{.*}} : $@convention(thin) (@in_guaranteed T, @in_guaranteed T) -> @out T { +// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T): +// CHECK: [[STACK_SLOT_0:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG0]] to [initialization] [[STACK_SLOT_0]] +// CHECK: [[STACK_SLOT_1:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG1]] to [initialization] [[STACK_SLOT_1]] +// CHECK: builtin "generic_fsub"([[RESULT]] : $*T, [[STACK_SLOT_0]] : $*T, [[STACK_SLOT_1]] : $*T) : $() +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}genericFsubTest{{.*}}' +func genericFsubTest(_ x : T, _ y : T) -> T { + return Builtin.generic_fsub(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}concreteUremTest{{.*}} : $@convention(thin) (Builtin.Int64, Builtin.Int64) -> Builtin.Int64 { +// CHECK: bb0([[ARG0:%.*]] : $Builtin.Int64, [[ARG1:%.*]] : $Builtin.Int64): +// CHECK: [[RESULT:%.*]] = builtin "generic_urem"([[ARG0]] : $Builtin.Int64, [[ARG1]] : $Builtin.Int64) : $Builtin.Int64 +// CHECK: return [[RESULT]] +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}concreteUremTest{{.*}}' +func concreteUremTest(_ x: Builtin.Int64, _ y: Builtin.Int64) -> Builtin.Int64 { + return Builtin.generic_urem(x, y) +} + +// CHECK-LABEL: sil hidden [ossa] @$s20polymorphic_builtins{{.*}}genericUremTest{{.*}} : $@convention(thin) (@in_guaranteed T, @in_guaranteed T) -> @out T { +// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T): +// CHECK: [[STACK_SLOT_0:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG0]] to [initialization] [[STACK_SLOT_0]] +// CHECK: [[STACK_SLOT_1:%.*]] = alloc_stack $T +// CHECK: copy_addr [[ARG1]] to [initialization] [[STACK_SLOT_1]] +// CHECK: builtin "generic_urem"([[RESULT]] : $*T, [[STACK_SLOT_0]] : $*T, [[STACK_SLOT_1]] : $*T) : $() +// CHECK: } // end sil function '$s20polymorphic_builtins{{.*}}genericUremTest{{.*}}' +func genericUremTest(_ x : T, _ y : T) -> T { + return Builtin.generic_urem(x, y) +} From 8fab074bb53f4d38b900b2f5b8f0352871cb5243 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 18 Sep 2019 19:21:20 -0400 Subject: [PATCH 092/199] AST: Fix regression from SubstFlags::UseErrorTypes removal Note that while the original crasher in the radar is gone, my reduced test case triggers an IRGen crash on both 5.1 and master because of an unrelated bug that appears to be related to protocol requirement signatures and declaration ordering. Fixes . --- lib/AST/SubstitutionMap.cpp | 5 +- .../0206-rdar54952911.swift | 49 +++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 validation-test/compiler_crashers_2_fixed/0206-rdar54952911.swift diff --git a/lib/AST/SubstitutionMap.cpp b/lib/AST/SubstitutionMap.cpp index 9d0ea0c2c2feb..8d06996328269 100644 --- a/lib/AST/SubstitutionMap.cpp +++ b/lib/AST/SubstitutionMap.cpp @@ -388,12 +388,15 @@ SubstitutionMap::lookupConformance(CanType type, ProtocolDecl *proto) const { if (conformance->isAbstract()) { // FIXME: Rip this out once we can get a concrete conformance from // an archetype. - auto *M = proto->getParentModule(); auto substType = type.subst(*this); + if (substType->hasError()) + return ProtocolConformanceRef(proto); + if ((!substType->is() || substType->castTo()->getSuperclass()) && !substType->isTypeParameter() && !substType->isExistentialType()) { + auto *M = proto->getParentModule(); return M->lookupConformance(substType, proto); } diff --git a/validation-test/compiler_crashers_2_fixed/0206-rdar54952911.swift b/validation-test/compiler_crashers_2_fixed/0206-rdar54952911.swift new file mode 100644 index 0000000000000..7859f338b3c12 --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/0206-rdar54952911.swift @@ -0,0 +1,49 @@ +// RUN: %target-swift-frontend -emit-silgen %s +// FIXME: Get the above to pass with -emit-ir too. + +public protocol P1 { + associatedtype A1: P3 where A1.A4.A3: P6 +} + +public protocol P12 : P1 where A1: P2 {} + +public protocol P2 : P3 where A3 == S3, A4: P4 {} + +public protocol P4 : P3 where A3 == S2, A4: P5 {} + +public protocol P5: P9 where A3 == S1 {} + +public protocol P6: P11 where A2: P7 {} + +public protocol P7: P8 {} + +public protocol P8 {} + +public protocol P11 { + associatedtype A2 : P8 +} + +public struct S1 : P11 {} + +public struct S2 : P11 {} + +extension S2: P6 where A2: P7 {} + +public struct S3 : P11 {} + +public protocol P9 { + associatedtype A2: P7 + associatedtype A3: P11 where A3.A2 == A2 +} + +public protocol P3 : P9 { + associatedtype A4: P9 where A4.A2 == A2 +} + +public protocol P10 { + associatedtype A3: P11 where A3.A2: P7 +} + +public struct S4 : P10 { + public typealias A3 = T.A1.A4.A3 +} From a7fce599f5ad4a8971a6cc4d6230f018d3cfbec7 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Thu, 19 Sep 2019 13:03:27 -0700 Subject: [PATCH 093/199] [SILGen] Properly substitute contextual archetypes when generating assign_by_wrapper Fixes SR-11303 / rdar://problem/54311335 --- lib/SILGen/SILGenLValue.cpp | 10 ++++++---- test/SILGen/property_wrappers.swift | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp index 6cdec0efc1cc4..5849093e0314b 100644 --- a/lib/SILGen/SILGenLValue.cpp +++ b/lib/SILGen/SILGenLValue.cpp @@ -1384,7 +1384,9 @@ namespace { VarDecl *field = dyn_cast(Storage); VarDecl *backingVar = field->getPropertyWrapperBackingProperty(); assert(backingVar); - CanType ValType = backingVar->getType()->getCanonicalType(); + CanType ValType = + SGF.F.mapTypeIntoContext(backingVar->getInterfaceType()) + ->getCanonicalType(); SILType varStorageType = SGF.SGM.Types.getSubstitutedStorageType(backingVar, ValType); auto typeData = @@ -1407,7 +1409,7 @@ namespace { assert(field->getAttachedPropertyWrappers().size() == 1); auto wrapperInfo = field->getAttachedPropertyWrapperTypeInfo(0); auto ctor = wrapperInfo.wrappedValueInit; - SubstitutionMap subs = backingVar->getType()->getMemberSubstitutionMap( + SubstitutionMap subs = ValType->getMemberSubstitutionMap( SGF.getModule().getSwiftModule(), ctor); Type ity = ctor->getInterfaceType(); @@ -1418,8 +1420,8 @@ namespace { .asForeign(requiresForeignEntryPoint(ctor)); RValue initFuncRV = SGF.emitApplyPropertyWrapperAllocator(loc, subs,initRef, - backingVar->getType(), - CanAnyFunctionType(substIty)); + ValType, + CanAnyFunctionType(substIty)); ManagedValue initFn = std::move(initFuncRV).getAsSingleValue(SGF, loc); // Create the allocating setter function. It captures the base address. diff --git a/test/SILGen/property_wrappers.swift b/test/SILGen/property_wrappers.swift index 785cb8e16a14b..7fc2488e6ba1b 100644 --- a/test/SILGen/property_wrappers.swift +++ b/test/SILGen/property_wrappers.swift @@ -447,6 +447,20 @@ public class Container { } } +// SR-11303 / rdar://problem/54311335 - crash due to wrong archetype used in generated SIL +public protocol TestProtocol {} +public class TestClass { + @WrapperWithInitialValue var value: T + + // CHECK-LABEL: sil hidden [ossa] @$s17property_wrappers9TestClassC5value8protocolACyxGx_qd__tcAA0C8ProtocolRd__lufc + // CHECK: metatype $@thin WrapperWithInitialValue.Type + // CHECK: function_ref @$s17property_wrappers23WrapperWithInitialValueV07wrappedF0ACyxGx_tcfCTc + init(value: T, protocol: U) { + self.value = value + } +} + + // CHECK-LABEL: sil_vtable ClassUsingWrapper { // CHECK-NEXT: #ClassUsingWrapper.x!getter.1: (ClassUsingWrapper) -> () -> Int : @$s17property_wrappers17ClassUsingWrapperC1xSivg // ClassUsingWrapper.x.getter // CHECK-NEXT: #ClassUsingWrapper.x!setter.1: (ClassUsingWrapper) -> (Int) -> () : @$s17property_wrappers17ClassUsingWrapperC1xSivs // ClassUsingWrapper.x.setter From 5e3b9b58bde9cf3f59f9726347e761a3a02c8a63 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Thu, 19 Sep 2019 13:44:54 -0700 Subject: [PATCH 094/199] [cmpcodesize] Allowed args to specify dirs. Previously, to specify the directories containing objects whose sizes should be compared, environment variables had to be used. With this change, arguments (-o/--old-build-dir, -n/--new-build-dir) can be passed to the cmpcodesize script directly. If those arguments aren't specified, the environment variables are sued as before. --- utils/cmpcodesize/cmpcodesize/main.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/utils/cmpcodesize/cmpcodesize/main.py b/utils/cmpcodesize/cmpcodesize/main.py index b9b9aca2392c2..13e10affb97f5 100644 --- a/utils/cmpcodesize/cmpcodesize/main.py +++ b/utils/cmpcodesize/cmpcodesize/main.py @@ -107,6 +107,18 @@ def main(): 'other programs.', action='store_true', default=False) + parser.add_argument('-o', '--old-build-directory', + help='The directory containing the baseline objects ' + + 'against which to compare sizes.', + action='store', + dest='old_build_dir', + default=None) + parser.add_argument('-n', '--new-build-directory', + help='The directory containing the new objects whose' + + 'sizes are to be compared against the baseline.', + action='store', + dest='new_build_dir', + default=None) # Positional arguments. # These can be specified in means beyond what argparse supports, @@ -145,8 +157,12 @@ def main(): else: old_file_args = parsed_arguments.files - old_build_dir = os.environ.get("SWIFT_OLD_BUILDDIR") - new_build_dir = os.environ.get("SWIFT_NEW_BUILDDIR") + old_build_dir = parsed_arguments.old_build_dir + if not old_build_dir: + old_build_dir = os.environ.get("SWIFT_OLD_BUILDDIR") + new_build_dir = parsed_arguments.new_build_dir + if not new_build_dir: + new_build_dir = os.environ.get("SWIFT_NEW_BUILDDIR") if not parsed_arguments.files: assert old_build_dir and new_build_dir, \ From 4ade7ae11f628b5f33d51de8e90489aa45039a2b Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Thu, 19 Sep 2019 16:31:41 -0700 Subject: [PATCH 095/199] [docs] CToSwift: swift_name for all top-level declarations (#27227) That is: types, globals, C functions, and enumerators, including a discussion of import-as-member for each. Still more to come: swift_name for properties, methods, and struct fields. --- docs/CToSwiftNameTranslation.md | 206 +++++++++++++++++++++++++++++++- 1 file changed, 205 insertions(+), 1 deletion(-) diff --git a/docs/CToSwiftNameTranslation.md b/docs/CToSwiftNameTranslation.md index e53e3441489df..ed3960f223d4c 100644 --- a/docs/CToSwiftNameTranslation.md +++ b/docs/CToSwiftNameTranslation.md @@ -1,6 +1,6 @@ # Name Translation from C to Swift -This document gives a high-level description of how C and Objective-C declarations are translated to Swift, with particular focus on how names are adjusted. It is not attempting to be a *complete* description of everything the compiler does except with regards to how *names* are transformed; even there, some special cases that only apply to Apple's SDKs have been omitted. +This document gives a high-level description of how C and Objective-C declarations are translated to Swift, with particular focus on how names are adjusted. It is not attempting to be a *complete* description of everything the compiler does except with regards to how *names* are transformed; even there, some special cases that only apply to Apple's SDKs have been omitted. The example code shown is for illustrative purposes and does not always include all parts of an imported API's interface. ## Word boundaries @@ -239,4 +239,208 @@ _The original intent of the `swift_private` attribute was additionally to limit _For "historical reasons", the `swift_private` attribute is ignored on factory methods with no arguments imported as initializers. This is essentially matching the behavior of older Swift compilers for source compatibility in case someone has marked such a factory method as `swift_private`._ +## Custom names + +The `swift_name` Clang attribute can be used to control how a declaration imports into Swift. If it's valid, the value of the `swift_name` attribute always overrides any other name transformation rules (prefix-stripping, underscore-prepending, etc.) + +### Types and globals + +The `swift_name` attribute can be used to give a type or a global a custom name. In the simplest form, the value of the attribute must be a valid Swift identifier. + +```objc +__attribute__((swift_name("SpacecraftCoordinates"))) +struct SPKSpacecraftCoordinates { + double x, y, z, t; // space and time, of course +}; +``` + +```swift +struct SpacecraftCoordinates { + var x, y, z, t: Double +} +``` + +### Import-as-member + +A custom name that starts with an identifier followed by a period is taken to be a member name. The identifier should be the imported Swift name of a C/Objective-C type in the same module. In this case, the type or global will be imported as a static member of the named type. + +```objc +__attribute__((swift_name("SpacecraftCoordinates.earth"))) +extern const struct SPKSpacecraftCoordinates SPKSpacecraftCoordinatesEarth; +``` + +```swift +extension SpacecraftCoordinates { + static var earth: SpacecraftCoordinates { get } +} +``` + +Note that types cannot be imported as members of protocols. + +_The "in the same module" restriction is considered a technical limitation; a forward declaration of the base type will work around it._ + + +### C functions with custom names + +The `swift_name` attribute can be used to give a C function a custom name. The value of the attribute must be a full Swift function name, including parameter labels. + +```objc +__attribute__((swift_name("doSomething(to:bar:)"))) +void doSomethingToFoo(Foo *foo, int bar); + +// Usually seen as NS_SWIFT_NAME. +``` + +```swift +func doSomething(foo: UnsafeMutablePointer, bar: Int32) +``` + +An underscore can be used in place of an empty parameter label, as in Swift. + +A C function with zero arguments and a non-`void` return type can also be imported as a computed variable by using the `getter:` prefix on the name. A function with one argument and a `void` return type can optionally serve as the setter for that variable using `setter:`. + +```objc +__attribute__((swift_name("getter:globalCounter()"))) +int getGlobalCounter(void); +__attribute__((swift_name("setter:globalCounter(_:)"))) +void setGlobalCounter(int newValue); +``` + +```swift +var globalCounter: Int32 { get set } +``` + +Note that the argument lists must still be present even though the name used is the name of the variable. (Also note the `void` parameter list to specify a C function with zero arguments. This is required!) + +Variables with setters and no getters are not supported. + + +#### Import-as-member + +Like types and globals, functions can be imported as static members of types. + +```objc +__attribute__((swift_name("NSSound.beep()"))) +void NSBeep(void); +``` + +```swift +extension NSSound { + static func beep() +} +``` + +However, by giving a parameter the label `self`, a function can also be imported as an instance member of a type __T__. In this case, the parameter labeled `self` must either have the type __T__ itself, or be a pointer to __T__. The latter is only valid if __T__ is imported as a value type; if the pointer is non-`const`, the resulting method will be `mutating`. If __T__ is a class, the function will be `final`. + +```objc +typedef struct { + int value; +} Counter; + +__attribute__((swift_name("Counter.printValue(self:)"))) +void CounterPrintValue(Counter c); +__attribute__((swift_name("Counter.printValue2(self:)"))) +void CounterPrintValue2(const Counter *c); +__attribute__((swift_name("Counter.resetValue(self:)"))) +void CounterResetValue(Counter *c); +``` + +```swift +struct Counter { + var value: Int32 { get set } +} + +extension Counter { + func printValue() + func printValue2() + mutating func resetValue() +} +``` + +This also applies to getters and setters, to be imported as instance properties. + +```objc +__attribute__((swift_name("getter:Counter.absoluteValue(self:)"))) +int CounterGetAbsoluteValue(Counter c); +``` + +```swift +extension Counter { + var absoluteValue: Int32 { get } +} +``` + +The getter/setter syntax also allows for subscripts by using the base name `subscript`. + +```objc +__attribute__((swift_name("getter:LinkedListOfInts.subscript(self:_:)"))) +int LinkedListGetAtIndex(const LinkedListOfInts *head, int index); +``` + +```swift +extension LinkedListOfInts { + subscript(_ index: Int32) -> Int32 { get } +} +``` + +Finally, functions can be imported as initializers as well by using the base name `init`. These are considered "factory" initializers and are never inherited or overridable. They must not have a `self` parameter. + +```objc +__attribute__((swift_name("Counter.init(initialValue:)"))) +Counter CounterCreateWithInitialValue(int value); +``` + +```swift +extension Counter { + /* non-inherited */ init(initialValue value: Int32) +} +``` + + +### Enumerators (enum cases) + +The `swift_name` attribute can be used to rename enumerators. As mentioned above, not only does no further prefix-stripping occur on the resulting name, but the presence of a custom name removes the enum case from the computation of a prefix for the other cases. + +``` +// Actual example from Apple's SDKs; in fact, the first shipping example of +// swift_name on an enumerator at all! +typedef NS_ENUM(NSUInteger, NSXMLNodeKind) { + NSXMLInvalidKind = 0, + NSXMLDocumentKind, + NSXMLElementKind, + NSXMLAttributeKind, + NSXMLNamespaceKind, + NSXMLProcessingInstructionKind, + NSXMLCommentKind, + NSXMLTextKind, + NSXMLDTDKind NS_SWIFT_NAME(DTDKind), + NSXMLEntityDeclarationKind, + NSXMLAttributeDeclarationKind, + NSXMLElementDeclarationKind, + NSXMLNotationDeclarationKind +}; +``` + +``` +public enum Kind : UInt { + case invalid + case document + case element + case attribute + case namespace + case processingInstruction + case comment + case text + case DTDKind + case entityDeclaration + case attributeDeclaration + case elementDeclaration + case notationDeclaration +} +``` + +Although enumerators always have global scope in C, they are often imported as members in Swift, and thus the `swift_name` attribute cannot be used to import them as members of another type unless the enum type is anonymous. + +_Currently, `swift_name` does not even allow importing an enum case as a member of the enum type itself, even if the enum is not recognized as an `@objc` enum, error code enum, or option set (i.e. the situation where a case is imported as a global constant)._ + ## More to come... From 74ced92abd3d68d67ac59042c279441b0aa98bba Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Thu, 19 Sep 2019 16:59:03 -0700 Subject: [PATCH 096/199] Revert "[sil] Teach the SILVerifier how to validate that a builtin insts are always mapped to a known builtin." This reverts commit e2a9a432209affcd5b427481795cc859bd5ae19d. Going to put a cache in front of this to ensure we aren't bloating compile time. Conflicts: lib/SIL/SILVerifier.cpp --- lib/SIL/SILVerifier.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp index b63fc7b9b9711..0cfecbc6c0302 100644 --- a/lib/SIL/SILVerifier.cpp +++ b/lib/SIL/SILVerifier.cpp @@ -1635,12 +1635,6 @@ class SILVerifier : public SILVerifierBase { return; } - // At this point, we know that we have a Builtin that is a Swift Builtin - // rather than an llvm intrinsic. Make sure our name corresponds to an - // actual ValueDecl. Otherwise, we have an invalid builtin. - require(getBuiltinValueDecl(BI->getModule().getASTContext(), BI->getName()), - "Invalid builtin name?!"); - require(BI->getModule().getStage() != SILStage::Lowered || !isPolymorphicBuiltin(*BI->getBuiltinKind()), "Polymorphic builtins are illegal in lowered SIL?!"); From 9864cb9c06180b68290502edb34188841111cd61 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Thu, 19 Sep 2019 14:13:05 -0700 Subject: [PATCH 097/199] [polymorphic-builtins] Teach constant folding how to fold a polymorphic builtin to its static overload if the passed in type is a concrete builtin type Specifically, this transforms: builtin "generic_add"( -> builtin "add_Vec4xInt32"( If we do not have a static overload for the type, we just leave the generic call alone. If the generic builtin takes addresses as its arguments (i.e. 2x in_guaranteed + 1x out), we load the arguments, evaluate the static overloaded builtin and then store the result into the out parameter. --- include/swift/SIL/InstructionUtils.h | 32 +++++ include/swift/SIL/SILInstruction.h | 28 +++- lib/SIL/InstructionUtils.cpp | 145 +++++++++++++++++++++ lib/SIL/SILVerifier.cpp | 20 +++ lib/SILOptimizer/Utils/ConstantFolding.cpp | 50 ++++++- test/SILOptimizer/polymorphic_builtins.sil | 54 ++++++++ 6 files changed, 327 insertions(+), 2 deletions(-) create mode 100644 test/SILOptimizer/polymorphic_builtins.sil diff --git a/include/swift/SIL/InstructionUtils.h b/include/swift/SIL/InstructionUtils.h index affe24e8ac957..2690d571881b8 100644 --- a/include/swift/SIL/InstructionUtils.h +++ b/include/swift/SIL/InstructionUtils.h @@ -142,6 +142,38 @@ bool onlyUsedByAssignByWrapper(PartialApplyInst *PAI); void findClosuresForFunctionValue(SILValue V, TinyPtrVector &results); +/// Given a polymorphic builtin \p bi that may be generic and thus have in/out +/// params, stash all of the information needed for either specializing while +/// inlining or propagating the type in constant propagation. +/// +/// NOTE: If we perform this transformation, our builtin will no longer have any +/// substitutions since we only substitute to concrete static overloads. +struct PolymorphicBuiltinSpecializedOverloadInfo { + Identifier staticOverloadIdentifier; + SmallVector argTypes; + SILType resultType; + bool hasOutParam = false; + +#ifndef NDEBUG +private: + bool isInitialized = false; +#endif + +public: + PolymorphicBuiltinSpecializedOverloadInfo() = default; + + bool init(SILFunction *fn, BuiltinValueKind builtinKind, + ArrayRef oldOperandTypes, SILType oldResultType); + + bool init(BuiltinInst *bi); +}; + +/// Given a polymorphic builtin \p bi, analyze its types and create a builtin +/// for the static overload that the builtin corresponds to. If \p bi is not a +/// polymorphic builtin or does not have any available overload for these types, +/// return SILValue(). +SILValue getStaticOverloadForSpecializedPolymorphicBuiltin(BuiltinInst *bi); + } // end namespace swift #endif diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index 4af8cc42acd56..ba58eb03d7301 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -523,6 +523,16 @@ class SILInstruction getAllOperands()[Num1].swap(getAllOperands()[Num2]); } +private: + /// Predicate used to filter OperandTypeRange. + struct OperandToType; + +public: + using OperandTypeRange = + OptionalTransformRange, OperandToType>; + // NOTE: We always skip type dependent operands. + OperandTypeRange getOperandTypes() const; + /// Return the list of results produced by this instruction. bool hasResults() const { return !getResults().empty(); } SILInstructionResultArray getResults() const { return getResultsImpl(); } @@ -700,6 +710,22 @@ SILInstruction::getOperandValues(bool skipTypeDependentOperands) const OperandToValue(*this, skipTypeDependentOperands)); } +struct SILInstruction::OperandToType { + const SILInstruction &i; + + OperandToType(const SILInstruction &i) : i(i) {} + + Optional operator()(const Operand &use) const { + if (i.isTypeDependentOperand(use)) + return None; + return use.get()->getType(); + } +}; + +inline auto SILInstruction::getOperandTypes() const -> OperandTypeRange { + return OperandTypeRange(getAllOperands(), OperandToType(*this)); +} + inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const SILInstruction &I) { I.print(OS); @@ -3007,7 +3033,7 @@ class BuiltinInst final /// Looks up the BuiltinKind of this builtin. Returns None if this is /// not a builtin. - llvm::Optional getBuiltinKind() const { + Optional getBuiltinKind() const { auto I = getBuiltinInfo(); if (I.ID == BuiltinValueKind::None) return None; diff --git a/lib/SIL/InstructionUtils.cpp b/lib/SIL/InstructionUtils.cpp index 1d9d47eacaae4..a7155f6ba25cf 100644 --- a/lib/SIL/InstructionUtils.cpp +++ b/lib/SIL/InstructionUtils.cpp @@ -14,10 +14,12 @@ #include "swift/SIL/InstructionUtils.h" #include "swift/AST/SubstitutionMap.h" #include "swift/Basic/NullablePtr.h" +#include "swift/Basic/STLExtras.h" #include "swift/SIL/DebugUtils.h" #include "swift/SIL/Projection.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBasicBlock.h" +#include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILVisitor.h" using namespace swift; @@ -530,3 +532,146 @@ void swift::findClosuresForFunctionValue( // Ignore other unrecognized values that feed this applied argument. } } + +bool PolymorphicBuiltinSpecializedOverloadInfo::init( + SILFunction *fn, BuiltinValueKind builtinKind, + ArrayRef oldOperandTypes, SILType oldResultType) { +#ifndef NDEBUG + assert(!isInitialized && "Expected uninitialized info"); + SWIFT_DEFER { isInitialized = true; }; +#endif + if (!isPolymorphicBuiltin(builtinKind)) + return false; + + // Ok, at this point we know that we have a true polymorphic builtin. See if + // we have an overload for its current operand type. + StringRef name = getBuiltinName(builtinKind); + StringRef prefix = "generic_"; + assert(name.startswith(prefix) && + "Invalid polymorphic builtin name! Prefix should be Generic$OP?!"); + SmallString<32> staticOverloadName; + staticOverloadName.append(name.drop_front(prefix.size())); + + // If our first argument is an address, we know we have an indirect @out + // parameter by convention since all of these polymorphic builtins today never + // take indirect parameters without an indirect out result parameter. We stash + // this information and validate that if we have an out param, that our result + // is equal to the empty tuple type. + if (oldOperandTypes[0].isAddress()) { + if (oldResultType != fn->getModule().Types.getEmptyTupleType()) + return false; + + hasOutParam = true; + SILType firstType = oldOperandTypes.front(); + + // We only handle polymorphic builtins with trivial types today. + if (!firstType.is() || !firstType.isTrivial(*fn)) { + return false; + } + + resultType = firstType.getObjectType(); + oldOperandTypes = oldOperandTypes.drop_front(); + } else { + resultType = oldResultType; + } + + // Then go through all of our values and bail if any after substitution are + // not concrete builtin types. Otherwise, stash each of them in the argTypes + // array as objects. We will convert them as appropriate. + for (SILType ty : oldOperandTypes) { + // If after specialization, we do not have a trivial builtin type, bail. + if (!ty.is() || !ty.isTrivial(*fn)) { + return false; + } + + // Otherwise, we have an object builtin type ready to go. + argTypes.push_back(ty.getObjectType()); + } + + // Ok, we have all builtin types. Infer the underlying polymorphic builtin + // name form our first argument. + CanBuiltinType builtinType = argTypes.front().getAs(); + SmallString<32> builtinTypeNameStorage; + StringRef typeName = builtinType->getTypeName(builtinTypeNameStorage, false); + staticOverloadName.append("_"); + staticOverloadName.append(typeName); + + auto &ctx = fn->getASTContext(); + staticOverloadIdentifier = ctx.getIdentifier(staticOverloadName); + return true; +} + +bool PolymorphicBuiltinSpecializedOverloadInfo::init(BuiltinInst *bi) { +#ifndef NDEBUG + assert(!isInitialized && "Can not init twice?!"); + SWIFT_DEFER { isInitialized = true; }; +#endif + + // First quickly make sure we have a /real/ BuiltinValueKind, not an intrinsic + // or None. + auto kind = bi->getBuiltinKind(); + if (!kind) + return false; + + SmallVector oldOperandTypes; + copy(bi->getOperandTypes(), std::back_inserter(oldOperandTypes)); + assert(bi->getNumResults() == 1 && + "We expect a tuple here instead of real args"); + SILType oldResultType = bi->getResult(0)->getType(); + return init(bi->getFunction(), *kind, oldOperandTypes, oldResultType); +} + +SILValue +swift::getStaticOverloadForSpecializedPolymorphicBuiltin(BuiltinInst *bi) { + + PolymorphicBuiltinSpecializedOverloadInfo info; + if (!info.init(bi)) + return SILValue(); + + SmallVector rawArgsData; + copy(bi->getOperandValues(), std::back_inserter(rawArgsData)); + + SILValue result = bi->getResult(0); + MutableArrayRef rawArgs = rawArgsData; + + if (info.hasOutParam) { + result = rawArgs.front(); + rawArgs = rawArgs.drop_front(); + } + + assert(bi->getNumResults() == 1 && + "We assume that builtins have a single result today. If/when this " + "changes, this code needs to be updated"); + + SILBuilderWithScope builder(bi); + + // Ok, now we know that we can convert this to our specialized + // builtin. Prepare the arguments for the specialized value, loading the + // values if needed and storing the result into an out parameter if needed. + // + // NOTE: We only support polymorphic builtins with trivial types today, so we + // use load/store trivial as a result. + SmallVector newArgs; + for (SILValue arg : rawArgs) { + if (arg->getType().isObject()) { + newArgs.push_back(arg); + continue; + } + + SILValue load = builder.emitLoadValueOperation( + bi->getLoc(), arg, LoadOwnershipQualifier::Trivial); + newArgs.push_back(load); + } + + BuiltinInst *newBI = + builder.createBuiltin(bi->getLoc(), info.staticOverloadIdentifier, + info.resultType, {}, newArgs); + + // If we have an out parameter initialize it now. + if (info.hasOutParam) { + builder.emitStoreValueOperation(newBI->getLoc(), newBI->getResult(0), + result, StoreOwnershipQualifier::Trivial); + } + + return newBI; +} diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp index 0cfecbc6c0302..ab0a1fc5bef68 100644 --- a/lib/SIL/SILVerifier.cpp +++ b/lib/SIL/SILVerifier.cpp @@ -500,7 +500,27 @@ struct ImmutableAddressUseVerifier { if (inst->isTypeDependentOperand(*use)) continue; + // TODO: Can this switch be restructured so break -> error, continue -> + // next iteration, return -> return the final result. switch (inst->getKind()) { + case SILInstructionKind::BuiltinInst: { + // If we are processing a polymorphic builtin that takes an address, + // skip the builtin. This is because the builtin must be specialized to + // a non-memory reading builtin that works on trivial object values + // before the diagnostic passes end (or be DCEed) or we emit a + // diagnostic. + if (auto builtinKind = cast(inst)->getBuiltinKind()) { + if (isPolymorphicBuiltin(*builtinKind)) { + break; + } + } + + // Otherwise this is a builtin that we are not expecting to see, so bail + // and assert. + llvm::errs() << "Unhandled, unexpected builtin instruction: " << *inst; + llvm_unreachable("invoking standard assertion failure"); + break; + } case SILInstructionKind::MarkDependenceInst: case SILInstructionKind::LoadBorrowInst: case SILInstructionKind::DebugValueAddrInst: diff --git a/lib/SILOptimizer/Utils/ConstantFolding.cpp b/lib/SILOptimizer/Utils/ConstantFolding.cpp index 50d846ec13937..a453e4b73cc0c 100644 --- a/lib/SILOptimizer/Utils/ConstantFolding.cpp +++ b/lib/SILOptimizer/Utils/ConstantFolding.cpp @@ -14,6 +14,7 @@ #include "swift/AST/DiagnosticsSIL.h" #include "swift/AST/Expr.h" +#include "swift/SIL/InstructionUtils.h" #include "swift/SIL/PatternMatch.h" #include "swift/SIL/SILBuilder.h" #include "swift/SILOptimizer/Utils/CastOptimizer.h" @@ -23,7 +24,7 @@ #include "llvm/ADT/Statistic.h" #include "llvm/Support/Debug.h" -#define DEBUG_TYPE "constant-folding" +#define DEBUG_TYPE "sil-constant-folding" using namespace swift; @@ -582,6 +583,21 @@ constantFoldAndCheckDivision(BuiltinInst *BI, BuiltinValueKind ID, return B.createIntegerLiteral(BI->getLoc(), BI->getType(), ResVal); } +static SILValue specializePolymorphicBuiltin(BuiltinInst *bi, + BuiltinValueKind id, + Optional &resultsInError) { + // If we are not a polymorphic builtin, return an empty SILValue() + // so we keep on scanning. + if (!isPolymorphicBuiltin(id)) + return SILValue(); + + // Otherwise, try to perform the mapping. + if (auto newBuiltin = getStaticOverloadForSpecializedPolymorphicBuiltin(bi)) + return newBuiltin; + + return SILValue(); +} + /// Fold binary operations. /// /// The list of operations we constant fold might not be complete. Start with @@ -1593,6 +1609,15 @@ void ConstantFolder::initializeWorklist(SILFunction &f) { continue; } + if (auto *bi = dyn_cast(inst)) { + if (auto kind = bi->getBuiltinKind()) { + if (isPolymorphicBuiltin(kind.getValue())) { + WorkList.insert(bi); + continue; + } + } + } + // If we have nominal type literals like struct, tuple, enum visit them // like we do in the worklist to see if we can fold any projection // manipulation operations. @@ -1804,6 +1829,29 @@ ConstantFolder::processWorkList() { continue; } + if (auto *bi = dyn_cast(I)) { + if (auto kind = bi->getBuiltinKind()) { + Optional ResultsInError; + if (EnableDiagnostics) + ResultsInError = false; + if (SILValue v = specializePolymorphicBuiltin(bi, kind.getValue(), + ResultsInError)) { + // If bi had a result, RAUW. + if (bi->getResult(0)->getType() != + bi->getModule().Types.getEmptyTupleType()) + bi->replaceAllUsesWith(v); + // Then delete no matter what. + bi->eraseFromParent(); + InvalidateInstructions = true; + } + + // If we did not pass in a None and the optional is set to true, add the + // user to our error set. + if (ResultsInError.hasValue() && ResultsInError.getValue()) + ErrorSet.insert(bi); + } + } + // Go through all users of the constant and try to fold them. FoldedUsers.clear(); for (auto Result : I->getResults()) { diff --git a/test/SILOptimizer/polymorphic_builtins.sil b/test/SILOptimizer/polymorphic_builtins.sil new file mode 100644 index 0000000000000..6b42ca9dbb6cf --- /dev/null +++ b/test/SILOptimizer/polymorphic_builtins.sil @@ -0,0 +1,54 @@ +// RUN: %target-sil-opt -module-name Swift -diagnostic-constant-propagation %s | %FileCheck %s + +sil_stage raw + +import Builtin + +struct MyInt { + var i : Builtin.Int32 +} + +// CHECK-LABEL: sil @concrete_type_object_test : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +// CHECK: builtin "add_Vec4xInt32"( +// CHECK: return +// CHECK: } // end sil function 'concrete_type_object_test' +sil @concrete_type_object_test : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +bb0(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32): + %2 = builtin "generic_add"(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 + return %2 : $Builtin.Vec4xInt32 +} + +// CHECK-LABEL: sil @concrete_type_address_test : $@convention(thin) (@in_guaranteed Builtin.Vec4xInt32, @in_guaranteed Builtin.Vec4xInt32) -> @out Builtin.Vec4xInt32 { +// CHECK: bb0([[RESULT:%.*]] : $*Builtin.Vec4xInt32, [[ARG0:%.*]] : $*Builtin.Vec4xInt32, [[ARG1:%.*]] : $*Builtin.Vec4xInt32): +// CHECK: [[LOADED_ARG0:%.*]] = load [[ARG0]] +// CHECK: [[LOADED_ARG1:%.*]] = load [[ARG1]] +// CHECK: [[LOADED_RESULT:%.*]] = builtin "add_Vec4xInt32"([[LOADED_ARG0]] : $Builtin.Vec4xInt32, [[LOADED_ARG1]] : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 +// CHECK: store [[LOADED_RESULT]] to [[RESULT]] +// CHECK: } // end sil function 'concrete_type_address_test' +sil @concrete_type_address_test : $@convention(thin) (@in_guaranteed Builtin.Vec4xInt32, @in_guaranteed Builtin.Vec4xInt32) -> @out Builtin.Vec4xInt32 { +bb0(%0 : $*Builtin.Vec4xInt32, %1 : $*Builtin.Vec4xInt32, %2 : $*Builtin.Vec4xInt32): + builtin "generic_add"(%0 : $*Builtin.Vec4xInt32, %1 : $*Builtin.Vec4xInt32, %2 : $*Builtin.Vec4xInt32) : $() + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil @concrete_type_object_fail : $@convention(thin) (MyInt, MyInt) -> MyInt { +// CHECK: builtin "generic_add"( +// CHECK: return +// CHECK: } // end sil function 'concrete_type_object_fail' +sil @concrete_type_object_fail : $@convention(thin) (MyInt, MyInt) -> MyInt { +bb0(%0 : $MyInt, %1 : $MyInt): + %2 = builtin "generic_add"(%0 : $MyInt, %1 : $MyInt) : $MyInt + return %2 : $MyInt +} + +// CHECK-LABEL: sil @concrete_type_address_fail : $@convention(thin) (@in_guaranteed MyInt, @in_guaranteed MyInt) -> @out MyInt { +// CHECK: builtin "generic_add"( +// CHECK: return +// CHECK: } // end sil function 'concrete_type_address_fail' +sil @concrete_type_address_fail : $@convention(thin) (@in_guaranteed MyInt, @in_guaranteed MyInt) -> @out MyInt { +bb0(%0 : $*MyInt, %1 : $*MyInt, %2 : $*MyInt): + %3 = builtin "generic_add"(%0 : $*MyInt, %1 : $*MyInt, %2 : $*MyInt) : $() + %9999 = tuple() + return %9999 : $() +} From daff289bc15df09c13bd3ade1fecb5cfeab80fa2 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Thu, 19 Sep 2019 18:04:45 -0700 Subject: [PATCH 098/199] [ClangImporter] Update old comments and remove obsolete FIXMEs --- lib/ClangImporter/ImportType.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index e0ab429b35f9f..f46d78f6af617 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -384,9 +384,7 @@ namespace { } // All other C pointers to concrete types map to - // UnsafeMutablePointer or OpaquePointer (FIXME:, except in - // parameter position under the pre- - // intrinsic-pointer-conversion regime.) + // UnsafeMutablePointer or OpaquePointer. // With pointer conversions enabled, map to the normal pointer types // without special hints. @@ -478,9 +476,6 @@ namespace { } ImportResult VisitConstantArrayType(const clang::ConstantArrayType *type) { - // FIXME: In a function argument context, arrays should import as - // pointers. - // FIXME: Map to a real fixed-size Swift array type when we have those. // Importing as a tuple at least fills the right amount of space, and // we can cheese static-offset "indexing" using .$n operations. @@ -545,8 +540,7 @@ namespace { if (type->isVariadic()) return Type(); - // Import the result type. We currently provide no mechanism - // for this to be audited. + // Import the result type. auto resultTy = Impl.importTypeIgnoreIUO( type->getReturnType(), ImportTypeKind::Result, AllowNSUIntegerAsInt, Bridging, OTK_Optional); @@ -566,7 +560,7 @@ namespace { // FIXME: If we were walking TypeLocs, we could actually get parameter // names. The probably doesn't matter outside of a FuncDecl, which // we'll have to special-case, but it's an interesting bit of data loss. - // We also lose `noescape`. + // params.push_back(FunctionType::Param(swiftParamTy)); } @@ -637,8 +631,8 @@ namespace { ImportResult VisitObjCTypeParamType(const clang::ObjCTypeParamType *type) { // FIXME: This drops any added protocols on the floor, which is the whole - // point of ObjCTypeParamType. When not in Swift 3 compatibility mode, we - // should adjust the resulting type accordingly. + // point of ObjCTypeParamType. Fixing this might be source-breaking, + // though. rdar://problem/29763975 if (auto result = importObjCTypeParamDecl(type->getDecl())) return result.getValue(); // Fall back to importing the desugared type, which uses the parameter's From 311607ec40541d06008da3a8f0006f3f1fa335cc Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Thu, 19 Sep 2019 18:21:10 -0700 Subject: [PATCH 099/199] [ClangImporter] Simplify typedef bridgeability checking A typedef might get imported as an alias for a bridged type (String) or for the original type (NSString), and a few parts of the importer need to account for this. Simplify this logic based on how it's used today. --- lib/ClangImporter/ImportDecl.cpp | 8 ++++---- lib/ClangImporter/ImportType.cpp | 14 ++------------ lib/ClangImporter/ImporterImpl.h | 19 +++++++++---------- 3 files changed, 15 insertions(+), 26 deletions(-) diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index a1a8021467421..fb3eecc5b6a24 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -2634,13 +2634,13 @@ namespace { return newtype; if (!SwiftType) { - // Import typedefs of blocks as their fully-bridged equivalent Swift - // type. That matches how we want to use them in most cases. All other - // types should be imported in a non-bridged way. + // Note that the code below checks to see if the typedef allows + // bridging, i.e. if the imported typealias should name a bridged type + // or the original C type. clang::QualType ClangType = Decl->getUnderlyingType(); SwiftType = Impl.importTypeIgnoreIUO( ClangType, ImportTypeKind::Typedef, isInSystemModule(DC), - getTypedefBridgeability(Decl, ClangType), OTK_Optional); + getTypedefBridgeability(Decl), OTK_Optional); } if (!SwiftType) diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index f46d78f6af617..1cb884e096014 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -725,23 +725,13 @@ namespace { // Otherwise, recurse on the underlying type. We need to recompute // the hint, and if the typedef uses different bridgeability than the // context then we may also need to bypass the typedef. - auto underlyingType = type->desugar(); - - // Figure out the bridgeability we would normally use for this typedef. - auto typedefBridgeability = - getTypedefBridgeability(type->getDecl(), underlyingType); - - // Figure out the typedef we should actually use. - auto underlyingBridgeability = Bridging; - SwiftTypeConverter innerConverter(Impl, AllowNSUIntegerAsInt, - underlyingBridgeability); - auto underlyingResult = innerConverter.Visit(underlyingType); + auto underlyingResult = Visit(type->desugar()); // If we used different bridgeability than this typedef normally // would because we're in a non-bridgeable context, and therefore // the underlying type is different from the mapping of the typedef, // use the underlying type. - if (underlyingBridgeability != typedefBridgeability && + if (Bridging != getTypedefBridgeability(type->getDecl()) && !underlyingResult.AbstractType->isEqual(mappedType)) { return underlyingResult; } diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index bac23850f54b9..6f774a85f33b6 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -178,19 +178,18 @@ enum class ImportTypeKind { Enum }; -/// Controls whether a typedef for \p type should name the fully-bridged Swift -/// type or the original Clang type. +/// Controls whether \p decl, when imported, should name the fully-bridged +/// Swift type or the original Clang type. /// /// In either case we end up losing sugar at some uses sites, so this is more /// about what the right default is. -static inline Bridgeability getTypedefBridgeability( - const clang::TypedefNameDecl *decl, - clang::QualType type) { - return decl->hasAttr() - ? Bridgeability::Full - : type->isBlockPointerType() - ? Bridgeability::Full - : Bridgeability::None; +static inline Bridgeability +getTypedefBridgeability(const clang::TypedefNameDecl *decl) { + if (decl->hasAttr() || + decl->getUnderlyingType()->isBlockPointerType()) { + return Bridgeability::Full; + } + return Bridgeability::None; } /// Describes the kind of the C type that can be mapped to a stdlib From a8496d43358730b51092150691496c6c026ac706 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Thu, 19 Sep 2019 18:22:16 -0700 Subject: [PATCH 100/199] [ClangImporter] Simplify a SmallVector fill to allocate up front No functionality change. --- lib/ClangImporter/ImportType.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index 1cb884e096014..bcbad64a92905 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -493,11 +493,7 @@ namespace { if (size > 4096) return Type(); - TupleTypeElt elt(elementType); - SmallVector elts; - for (size_t i = 0; i < size; ++i) - elts.push_back(elt); - + SmallVector elts{size, elementType}; return TupleType::get(elts, elementType->getASTContext()); } From 4a92e4f5355afffc6b2c812f399b0d668c9eeb4f Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Thu, 19 Sep 2019 18:34:42 -0700 Subject: [PATCH 101/199] [ClangImporter] Simplify helper method signature No functionality change. --- lib/ClangImporter/ImportType.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index bcbad64a92905..8239dbc7e8432 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -1183,10 +1183,12 @@ static bool isNSString(Type type) { } static ImportedType adjustTypeForConcreteImport( - ClangImporter::Implementation &impl, clang::QualType clangType, - Type importedType, ImportTypeKind importKind, ImportHint hint, + ClangImporter::Implementation &impl, + ImportResult importResult, ImportTypeKind importKind, bool allowNSUIntegerAsInt, Bridgeability bridging, OptionalTypeKind optKind, bool resugarNSErrorPointer) { + Type importedType = importResult.AbstractType; + ImportHint hint = importResult.Hint; if (importKind == ImportTypeKind::Abstract) { return {importedType, false}; @@ -1467,8 +1469,8 @@ ImportedType ClangImporter::Implementation::importType( // Now fix up the type based on how we're concretely using it. auto adjustedType = adjustTypeForConcreteImport( - *this, type, importResult.AbstractType, importKind, importResult.Hint, - allowNSUIntegerAsInt, bridging, optionality, resugarNSErrorPointer); + *this, importResult, importKind, allowNSUIntegerAsInt, bridging, + optionality, resugarNSErrorPointer); return adjustedType; } From d74107567c6169cec8da67190cb4750fa1b1e75d Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Thu, 19 Sep 2019 18:40:36 -0700 Subject: [PATCH 102/199] [ClangImporter] Simplify block pointer importing ever so slightly No need to make a whole separate SwiftTypeConverter; just use the one we already have. --- lib/ClangImporter/ImportType.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index 8239dbc7e8432..db8e5e4998184 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -444,9 +444,7 @@ namespace { ImportResult VisitBlockPointerType(const clang::BlockPointerType *type) { // Block pointer types are mapped to function types. - Type pointeeType = Impl.importTypeIgnoreIUO( - type->getPointeeType(), ImportTypeKind::Abstract, - AllowNSUIntegerAsInt, Bridging); + Type pointeeType = Visit(type->getPointeeType()).AbstractType; if (!pointeeType) return Type(); FunctionType *fTy = pointeeType->castTo(); From f919b2ddd866dbf90a38612a4ba711253e85d280 Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Wed, 18 Sep 2019 10:40:46 -0700 Subject: [PATCH 103/199] [SyntaxParse] Parse generic parameter clause and generic where clause --- cmake/modules/SwiftHandleGybSources.cmake | 2 + include/swift/Parse/ASTGen.h | 24 +- include/swift/Parse/Lexer.h | 4 +- .../swift/Parse/ParsedSyntaxBuilders.h.gyb | 2 +- include/swift/Parse/ParsedSyntaxNodes.h.gyb | 6 +- .../swift/Parse/ParsedSyntaxRecorder.h.gyb | 2 +- include/swift/Parse/Parser.h | 24 +- include/swift/Syntax/SyntaxBuilders.h.gyb | 2 +- include/swift/Syntax/SyntaxFactory.h.gyb | 2 +- include/swift/Syntax/SyntaxKind.h.gyb | 14 +- include/swift/Syntax/SyntaxNodes.h.gyb | 6 +- include/swift/Syntax/SyntaxVisitor.h.gyb | 2 +- lib/Parse/ASTGen.cpp | 195 +++++++- lib/Parse/ParseDecl.cpp | 1 + lib/Parse/ParseGeneric.cpp | 458 +++++++++--------- lib/Parse/ParseType.cpp | 114 ++--- lib/Parse/ParsedSyntaxBuilders.cpp.gyb | 2 +- lib/Parse/ParsedSyntaxNodes.cpp.gyb | 2 +- lib/Parse/ParsedSyntaxRecorder.cpp.gyb | 4 +- lib/Parse/Parser.cpp | 2 +- lib/ParseSIL/ParseSIL.cpp | 6 +- lib/Syntax/SyntaxBuilders.cpp.gyb | 2 +- lib/Syntax/SyntaxFactory.cpp.gyb | 10 +- lib/Syntax/SyntaxKind.cpp.gyb | 8 +- lib/Syntax/SyntaxNodes.cpp.gyb | 2 +- lib/Syntax/SyntaxVisitor.cpp.gyb | 4 +- test/Parse/invalid.swift | 2 +- .../round_trip_parse_gen.swift.withkinds | 22 +- unittests/Syntax/DeclSyntaxTests.cpp | 6 +- utils/gyb_syntax_support/GenericNodes.py | 55 ++- .../NodeSerializationCodes.py | 3 + utils/gyb_syntax_support/SILOnlyNodes.py | 9 + utils/gyb_syntax_support/__init__.py | 1 + 33 files changed, 634 insertions(+), 364 deletions(-) create mode 100644 utils/gyb_syntax_support/SILOnlyNodes.py diff --git a/cmake/modules/SwiftHandleGybSources.cmake b/cmake/modules/SwiftHandleGybSources.cmake index 1d37e4ae80958..7e858badf8e81 100644 --- a/cmake/modules/SwiftHandleGybSources.cmake +++ b/cmake/modules/SwiftHandleGybSources.cmake @@ -121,7 +121,9 @@ function(handle_gyb_sources dependency_out_var_name sources_var_name arch) "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/DeclNodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/ExprNodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/GenericNodes.py" + "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/NodeSerializationCodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/PatternNodes.py" + "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/SILOnlyNodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/StmtNodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/TypeNodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/Token.py" diff --git a/include/swift/Parse/ASTGen.h b/include/swift/Parse/ASTGen.h index 4f29a8bb3a8b0..591c8034548ea 100644 --- a/include/swift/Parse/ASTGen.h +++ b/include/swift/Parse/ASTGen.h @@ -22,21 +22,24 @@ namespace swift { /// Generates AST nodes from Syntax nodes. +class Parser; class ASTGen { ASTContext &Context; /// Type cache to prevent multiple transformations of the same syntax node. llvm::DenseMap TypeCache; - PersistentParserState **ParserState; + Parser &P; // FIXME: remove when Syntax can represent all types and ASTGen can handle them /// Types that cannot be represented by Syntax or generated by ASTGen. llvm::DenseMap Types; + llvm::DenseMap ParsedDeclAttrs; + public: - ASTGen(ASTContext &Context, PersistentParserState **ParserState) - : Context(Context), ParserState(ParserState) {} + ASTGen(ASTContext &Context, Parser &P) + : Context(Context), P(P) {} SourceLoc generate(syntax::TokenSyntax Tok, SourceLoc &Loc); @@ -70,6 +73,15 @@ class ASTGen { llvm::SmallVector generate(syntax::GenericArgumentListSyntax Args, SourceLoc &Loc); + GenericParamList * + generate(syntax::GenericParameterClauseListSyntax clause, SourceLoc &Loc); + GenericParamList * + generate(syntax::GenericParameterClauseSyntax clause, SourceLoc &Loc); + Optional + generate(syntax::GenericRequirementSyntax req, SourceLoc &Loc); + LayoutConstraint + generate(syntax::LayoutConstraintSyntax req, SourceLoc &Loc); + /// Copy a numeric literal value into AST-owned memory, stripping underscores /// so the semantic part of the value can be parsed by APInt/APFloat parsers. static StringRef copyAndStripUnderscores(StringRef Orig, ASTContext &Context); @@ -102,6 +114,8 @@ class ASTGen { ValueDecl *lookupInScope(DeclName Name); + void addToScope(ValueDecl *D, bool diagnoseRedefinitions = true); + TypeRepr *cacheType(syntax::TypeSyntax Type, TypeRepr *TypeAST); TypeRepr *lookupType(syntax::TypeSyntax Type); @@ -112,6 +126,10 @@ class ASTGen { bool hasType(const SourceLoc &Loc) const; TypeRepr *getType(const SourceLoc &Loc) const; + + void addDeclAttributes(DeclAttributes attrs, SourceLoc Loc); + bool hasDeclAttributes(SourceLoc Loc) const; + DeclAttributes getDeclAttributes(SourceLoc Loc) const; }; } // namespace swift diff --git a/include/swift/Parse/Lexer.h b/include/swift/Parse/Lexer.h index 8441a12dc17d4..2849c41f1eca3 100644 --- a/include/swift/Parse/Lexer.h +++ b/include/swift/Parse/Lexer.h @@ -200,8 +200,8 @@ class Lexer { ParsedTrivia &TrailingTriviaResult) { Result = NextToken; if (TriviaRetention == TriviaRetentionMode::WithTrivia) { - LeadingTriviaResult = {LeadingTrivia}; - TrailingTriviaResult = {TrailingTrivia}; + std::swap(LeadingTriviaResult, LeadingTrivia); + std::swap(TrailingTriviaResult, TrailingTrivia); } if (Result.isNot(tok::eof)) lexImpl(); diff --git a/include/swift/Parse/ParsedSyntaxBuilders.h.gyb b/include/swift/Parse/ParsedSyntaxBuilders.h.gyb index 90aba5e9eb212..0cfcf69bd32ce 100644 --- a/include/swift/Parse/ParsedSyntaxBuilders.h.gyb +++ b/include/swift/Parse/ParsedSyntaxBuilders.h.gyb @@ -30,7 +30,7 @@ namespace swift { class ParsedRawSyntaxRecorder; class SyntaxParsingContext; -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.is_buildable(): % child_count = len(node.children) class Parsed${node.name}Builder { diff --git a/include/swift/Parse/ParsedSyntaxNodes.h.gyb b/include/swift/Parse/ParsedSyntaxNodes.h.gyb index 5bbc07321f49d..8883b2ed796e8 100644 --- a/include/swift/Parse/ParsedSyntaxNodes.h.gyb +++ b/include/swift/Parse/ParsedSyntaxNodes.h.gyb @@ -28,20 +28,20 @@ namespace swift { % # Emit the non-collection classes first, then emit the collection classes % # that reference these classes. -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if not node.is_syntax_collection(): class Parsed${node.name}; % end % end -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.is_syntax_collection(): using Parsed${node.name} = ParsedSyntaxCollection; % end % end -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if not node.is_syntax_collection(): % qualifier = "" if node.is_base() else "final" % for line in dedented_lines(node.description): diff --git a/include/swift/Parse/ParsedSyntaxRecorder.h.gyb b/include/swift/Parse/ParsedSyntaxRecorder.h.gyb index 51b56c73aea07..5600ade0b5028 100644 --- a/include/swift/Parse/ParsedSyntaxRecorder.h.gyb +++ b/include/swift/Parse/ParsedSyntaxRecorder.h.gyb @@ -31,7 +31,7 @@ class SyntaxParsingContext; struct ParsedSyntaxRecorder { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.children: % child_params = [] % for child in node.children: diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 9ccac31e34256..91ee72590704c 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -695,11 +695,19 @@ class Parser { /// plain Tok.is(T1) check). bool skipUntilTokenOrEndOfLine(tok T1); + //-------------------------------------------------------------------------// + // Ignore token APIs. + // This is used when we skip gabage text in the source text. + + /// Ignore the current single token. void ignoreToken(); void ignoreToken(tok Kind) { + /// Ignore the current single token asserting its kind. assert(Tok.is(Kind)); ignoreToken(); } + /// Conditionally ignore the current single token if it matches with the \p + /// Kind. bool ignoreIf(tok Kind) { if (!Tok.is(Kind)) return false; @@ -1173,7 +1181,8 @@ class Parser { using TypeASTResult = ParserResult; using TypeResult = ParsedSyntaxResult; - LayoutConstraint parseLayoutConstraint(Identifier LayoutConstraintID); + ParsedSyntaxResult + parseLayoutConstraintSyntax(); TypeResult parseTypeSyntax(); TypeResult parseTypeSyntax(Diag<> MessageID, bool HandleCodeCompletion = true, @@ -1597,8 +1606,19 @@ class Parser { //===--------------------------------------------------------------------===// // Generics Parsing + ParserResult parseSILGenericParams(); + + ParserStatus parseSILGenericParamsSyntax( + Optional &result); + + ParsedSyntaxResult + parseGenericParameterClauseSyntax(); + + ParsedSyntaxResult + parseGenericWhereClauseSyntax(bool &FirstTypeInComplete, + bool AllowLayoutConstraints = false); + ParserResult parseGenericParameters(); - ParserResult parseGenericParameters(SourceLoc LAngleLoc); ParserStatus parseGenericParametersBeforeWhere(SourceLoc LAngleLoc, SmallVectorImpl &GenericParams); ParserResult maybeParseGenericParams(); diff --git a/include/swift/Syntax/SyntaxBuilders.h.gyb b/include/swift/Syntax/SyntaxBuilders.h.gyb index 7fe71ed159a3d..177d6779fe45e 100644 --- a/include/swift/Syntax/SyntaxBuilders.h.gyb +++ b/include/swift/Syntax/SyntaxBuilders.h.gyb @@ -29,7 +29,7 @@ namespace syntax { class SyntaxArena; -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.is_buildable(): % child_count = len(node.children) class ${node.name}Builder { diff --git a/include/swift/Syntax/SyntaxFactory.h.gyb b/include/swift/Syntax/SyntaxFactory.h.gyb index 387279d73f891..be88f173d5697 100644 --- a/include/swift/Syntax/SyntaxFactory.h.gyb +++ b/include/swift/Syntax/SyntaxFactory.h.gyb @@ -71,7 +71,7 @@ struct SyntaxFactory { static Syntax makeBlankCollectionSyntax(SyntaxKind Kind); -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.children: % child_params = [] % for child in node.children: diff --git a/include/swift/Syntax/SyntaxKind.h.gyb b/include/swift/Syntax/SyntaxKind.h.gyb index 21f344a572352..10291bad736b7 100644 --- a/include/swift/Syntax/SyntaxKind.h.gyb +++ b/include/swift/Syntax/SyntaxKind.h.gyb @@ -2,7 +2,7 @@ from gyb_syntax_support import * from gyb_syntax_support.kinds import SYNTAX_BASE_KINDS grouped_nodes = { kind: [] for kind in SYNTAX_BASE_KINDS } - for node in SYNTAX_NODES: + for node in SYNTAX_NODES + SILONLY_NODES: grouped_nodes[node.base_kind].append(node) # -*- mode: C++ -*- # Ignore the following admonition; it applies to the resulting .h file only @@ -89,12 +89,14 @@ struct WrapperTypeTraits { return 0; case syntax::SyntaxKind::Unknown: return 1; -% for name, nodes in grouped_nodes.items(): -% for node in nodes: +% for node in SYNTAX_NODES: case syntax::SyntaxKind::${node.syntax_kind}: return ${SYNTAX_NODE_SERIALIZATION_CODES[node.syntax_kind]}; -% end % end +% for node in SILONLY_NODES: + case syntax::SyntaxKind::${node.syntax_kind}: +% end + llvm_unreachable("unserializable syntax kind"); } llvm_unreachable("unhandled kind"); } @@ -122,6 +124,10 @@ struct ScalarReferenceTraits { case syntax::SyntaxKind::${node.syntax_kind}: return "\"${node.syntax_kind}\""; % end +% for node in SILONLY_NODES: + case syntax::SyntaxKind::${node.syntax_kind}: +% end + llvm_unreachable("unserializable syntax kind"); } llvm_unreachable("unhandled kind"); } diff --git a/include/swift/Syntax/SyntaxNodes.h.gyb b/include/swift/Syntax/SyntaxNodes.h.gyb index 65219ce8489d1..0e4a9a9bf5d54 100644 --- a/include/swift/Syntax/SyntaxNodes.h.gyb +++ b/include/swift/Syntax/SyntaxNodes.h.gyb @@ -32,13 +32,13 @@ namespace syntax { % # Emit the non-collection classes first, then emit the collection classes % # that reference these classes. -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if not node.is_syntax_collection(): class ${node.name}; % end % end -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.is_syntax_collection(): using ${node.name} = SyntaxCollection()) TypeAST = generate(*SimpleIdentifier, Loc); @@ -224,7 +223,7 @@ TypeRepr *ASTGen::generate(AttributedTypeSyntax Type, SourceLoc &Loc) { if (AttrKind == TAK_convention) { auto Argument = Attr.getArgument()->castTo(); - auto Convention = Context.getIdentifier(Argument.getText()); + auto Convention = Context.getIdentifier(Argument.getIdentifierText()); TypeAttrs.convention = Convention.str(); } @@ -339,9 +338,10 @@ TypeRepr *ASTGen::generateSimpleOrMemberIdentifier(T Type, SourceLoc &Loc) { auto FirstComponent = IdentType->getComponentRange().front(); // Lookup element #0 through our current scope chains in case it is some // thing local (this returns null if nothing is found). - if (auto Entry = lookupInScope(FirstComponent->getIdentifier())) + if (auto Entry = lookupInScope(FirstComponent->getIdentifier())) { if (auto *TD = dyn_cast(Entry)) FirstComponent->setValue(TD, nullptr); + } return IdentType; } @@ -369,6 +369,11 @@ TypeRepr *ASTGen::generate(SimpleTypeIdentifierSyntax Type, SourceLoc &Loc) { auto AnyLoc = advanceLocBegin(Loc, Type.getName()); return CompositionTypeRepr::createEmptyComposition(Context, AnyLoc); } + if (Type.getName().getText() == "class") { + auto classLoc = advanceLocBegin(Loc, Type.getName()); + return new (Context) SimpleIdentTypeRepr(classLoc, + Context.getIdentifier("AnyObject")); + } return generateSimpleOrMemberIdentifier(Type, Loc); } @@ -512,6 +517,162 @@ StringRef ASTGen::copyAndStripUnderscores(StringRef Orig, ASTContext &Context) { return StringRef(start, p - start); } +GenericParamList *ASTGen::generate(GenericParameterClauseListSyntax clauses, + SourceLoc &Loc) { + GenericParamList *curr = nullptr; + + // The first one is the outmost generic parameter list. + for (const auto &clause : clauses) { + auto params = generate(clause, Loc); + if (!params) + continue; + params->setOuterParameters(curr); + curr = params; + } + + return curr; +} + +GenericParamList *ASTGen::generate(GenericParameterClauseSyntax clause, + SourceLoc &Loc) { + SmallVector params; + params.reserve(clause.getGenericParameterList().getNumChildren()); + + for (auto elem : clause.getGenericParameterList()) { + + DeclAttributes attrs; + if (auto attrsSyntax = elem.getAttributes()) { + auto attrsLoc = advanceLocBegin(Loc, *attrsSyntax->getFirstToken()); + attrs = getDeclAttributes(attrsLoc); + } + Identifier name = Context.getIdentifier(elem.getName().getIdentifierText()); + SourceLoc nameLoc = advanceLocBegin(Loc, elem.getName()); + + // We always create generic type parameters with an invalid depth. + // Semantic analysis fills in the depth when it processes the generic + // parameter list. + auto param = new (Context) + GenericTypeParamDecl(P.CurDeclContext, name, nameLoc, + GenericTypeParamDecl::InvalidDepth, params.size()); + + if (auto inherited = elem.getInheritedType()) { + if (auto ty = generate(*inherited, Loc)) { + SmallVector constraints = {generate(*inherited, Loc)}; + param->setInherited(Context.AllocateCopy(constraints)); + } + } + + // Attach attributes. + param->getAttrs() = attrs; + + // Add this parameter to the scope. + addToScope(param); + + params.push_back(param); + } + if (params.empty()) + return nullptr; + + SourceLoc whereLoc; + SmallVector requirements; + if (auto whereClause = clause.getObsoletedWhereClause()) { + requirements.reserve(whereClause->getRequirementList().size()); + for (auto elem : whereClause->getRequirementList()) { + if (auto req = generate(elem, Loc)) + requirements.push_back(*req); + } + // There's an invariant that valid 'where' loc means that there's at + // at least one valid requirement. + if (!requirements.empty()) + whereLoc = advanceLocBegin(Loc, whereClause->getWhereKeyword()); + } + + auto lAngleLoc = advanceLocBegin(Loc, clause.getLeftAngleBracket()); + auto rAngleLoc = advanceLocBegin(Loc, clause.getRightAngleBracket()); + return GenericParamList::create(Context, lAngleLoc, params, whereLoc, + requirements, rAngleLoc); +} + +Optional ASTGen::generate(syntax::GenericRequirementSyntax req, + SourceLoc &Loc) { + if (auto sameTypeReq = req.getBody().getAs()) { + auto firstType = generate(sameTypeReq->getLeftTypeIdentifier(), Loc); + auto secondType = generate(sameTypeReq->getRightTypeIdentifier(), Loc); + if (!firstType || !secondType) + return None; + return RequirementRepr::getSameType( + firstType, advanceLocBegin(Loc, sameTypeReq->getEqualityToken()), + secondType); + } else if (auto conformanceReq = + req.getBody().getAs()) { + auto firstType = generate(conformanceReq->getLeftTypeIdentifier(), Loc); + auto secondType = generate(conformanceReq->getRightTypeIdentifier(), Loc); + if (!firstType || !secondType) + return None; + return RequirementRepr::getTypeConstraint( + firstType, advanceLocBegin(Loc, conformanceReq->getColon()), + secondType); + } else if (auto layoutReq = req.getBody().getAs()) { + auto firstType = generate(layoutReq->getLeftTypeIdentifier(), Loc); + auto layout = generate(layoutReq->getLayoutConstraint(), Loc); + if (!firstType || layout.isNull()) + return None; + auto colonLoc = advanceLocBegin(Loc, layoutReq->getColon()); + auto layoutLoc = advanceLocBegin(Loc, layoutReq->getLayoutConstraint()); + return RequirementRepr::getLayoutConstraint( + firstType, colonLoc, LayoutConstraintLoc(layout, layoutLoc)); + } else { + llvm_unreachable("invalid syntax kind for requirement body"); + } +} + +static LayoutConstraintKind getLayoutConstraintKind(Identifier &id, + ASTContext &Ctx) { + if (id == Ctx.Id_TrivialLayout) + return LayoutConstraintKind::TrivialOfExactSize; + if (id == Ctx.Id_TrivialAtMostLayout) + return LayoutConstraintKind::TrivialOfAtMostSize; + if (id == Ctx.Id_RefCountedObjectLayout) + return LayoutConstraintKind::RefCountedObject; + if (id == Ctx.Id_NativeRefCountedObjectLayout) + return LayoutConstraintKind::NativeRefCountedObject; + if (id == Ctx.Id_ClassLayout) + return LayoutConstraintKind::Class; + if (id == Ctx.Id_NativeClassLayout) + return LayoutConstraintKind::NativeClass; + return LayoutConstraintKind::UnknownLayout; +} + +LayoutConstraint ASTGen::generate(LayoutConstraintSyntax constraint, + SourceLoc &Loc) { + auto name = Context.getIdentifier(constraint.getName().getIdentifierText()); + auto constraintKind = getLayoutConstraintKind(name, Context); + assert(constraintKind != LayoutConstraintKind::UnknownLayout); + + // Non-trivial constraint kinds don't have size/alignment. + // TODO: Diagnose if it's supplied? + if (!LayoutConstraintInfo::isTrivial(constraintKind)) + return LayoutConstraint::getLayoutConstraint(constraintKind, Context); + + // '_Trivial' without explicit size/alignment. + if (!constraint.getSize()) + return LayoutConstraint::getLayoutConstraint(LayoutConstraintKind::Trivial, + Context); + + int size = 0; + if (auto sizeSyntax = constraint.getSize()) + sizeSyntax->getText().getAsInteger(10, size); + assert(size >= 0); + + int alignment = 0; + if (auto alignmentSyntax = constraint.getAlignment()) + alignmentSyntax->getText().getAsInteger(10, alignment); + assert(alignment >= 0); + + return LayoutConstraint::getLayoutConstraint(constraintKind, size, alignment, + Context); +} + SourceLoc ASTGen::advanceLocBegin(const SourceLoc &Loc, const Syntax &Node) { return Loc.getAdvancedLoc(Node.getAbsolutePosition().getOffset()); } @@ -550,9 +711,11 @@ MagicIdentifierLiteralExpr::Kind ASTGen::getMagicIdentifierLiteralKind(tok Kind) } ValueDecl *ASTGen::lookupInScope(DeclName Name) { - return Context.LangOpts.EnableASTScopeLookup && Context.LangOpts.DisableParserLookup - ? nullptr - : (*ParserState)->getScopeInfo().lookupValueName(Name); + return P.lookupInScope(Name); +} + +void ASTGen::addToScope(ValueDecl *D, bool diagnoseRedefinitions) { + P.addToScope(D, diagnoseRedefinitions); } TypeRepr *ASTGen::cacheType(TypeSyntax Type, TypeRepr *TypeAST) { @@ -576,3 +739,15 @@ bool ASTGen::hasType(const SourceLoc &Loc) const { TypeRepr *ASTGen::getType(const SourceLoc &Loc) const { return Types.find(Loc)->second; } + +void ASTGen::addDeclAttributes(DeclAttributes attrs, SourceLoc Loc) { + ParsedDeclAttrs.insert({Loc, attrs}); +} + +bool ASTGen::hasDeclAttributes(SourceLoc Loc) const { + return ParsedDeclAttrs.find(Loc) != ParsedDeclAttrs.end(); +} + +DeclAttributes ASTGen::getDeclAttributes(SourceLoc Loc) const { + return ParsedDeclAttrs.find(Loc)->second; +} diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 8400738a7a5b5..aac270c73ddae 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -16,6 +16,7 @@ #include "swift/Parse/Parser.h" #include "swift/Parse/CodeCompletionCallbacks.h" +#include "swift/Parse/ParsedSyntaxBuilders.h" #include "swift/Parse/ParsedSyntaxRecorder.h" #include "swift/Parse/ParseSILSupport.h" #include "swift/Parse/SyntaxParsingContext.h" diff --git a/lib/Parse/ParseGeneric.cpp b/lib/Parse/ParseGeneric.cpp index 912784c0ad044..ee00e32c6aad8 100644 --- a/lib/Parse/ParseGeneric.cpp +++ b/lib/Parse/ParseGeneric.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,185 +10,185 @@ // //===----------------------------------------------------------------------===// // -// Generic Parsing and AST Building +// Generic Parsing // //===----------------------------------------------------------------------===// #include "swift/Parse/Parser.h" #include "swift/AST/DiagnosticsParse.h" -#include "swift/Parse/CodeCompletionCallbacks.h" +#include "swift/Parse/ParsedSyntaxBuilders.h" +#include "swift/Parse/ParsedSyntaxRecorder.h" #include "swift/Parse/SyntaxParsingContext.h" -#include "swift/Parse/Lexer.h" -#include "swift/Syntax/SyntaxBuilders.h" -#include "swift/Syntax/SyntaxNodes.h" + using namespace swift; using namespace swift::syntax; -/// parseGenericParameters - Parse a sequence of generic parameters, e.g., -/// < T : Comparable, U : Container> along with an optional requires clause. +/// Parse a list of generic parameters. +/// +/// generic-parameter-clause-list: +/// generic-parameter-clause generic-parameter-clause* +ParserStatus Parser::parseSILGenericParamsSyntax( + Optional &result) { + assert(isInSILMode()); + ParserStatus status; + if (!startsWithLess(Tok)) + return status; + + SmallVector clauses; + do { + auto result = parseGenericParameterClauseSyntax(); + status |= result.getStatus(); + if (!result.isNull()) + clauses.push_back(result.get()); + } while (startsWithLess(Tok)); + + result = ParsedSyntaxRecorder::makeGenericParameterClauseList(clauses, + *SyntaxContext); + return status; +} + +/// Parse a sequence of generic parameters, e.g. '' +/// along with an optional requires clause. /// -/// generic-params: -/// '<' generic-param (',' generic-param)* where-clause? '>' +/// generic-parameter-clause: +/// '<' generic-paramter (',' generic-parameter)* where-clause? '>' /// -/// generic-param: +/// generic-parameter: /// identifier -/// identifier ':' type-identifier -/// identifier ':' type-composition -/// -/// When parsing the generic parameters, this routine establishes a new scope -/// and adds those parameters to the scope. -ParserResult Parser::parseGenericParameters() { - SyntaxParsingContext GPSContext(SyntaxContext, SyntaxKind::GenericParameterClause); - // Parse the opening '<'. +/// identifier ':' type +ParsedSyntaxResult +Parser::parseGenericParameterClauseSyntax() { assert(startsWithLess(Tok) && "Generic parameter list must start with '<'"); - return parseGenericParameters(consumeStartingLess()); -} + ParsedGenericParameterClauseSyntaxBuilder builder(*SyntaxContext); + ParserStatus status; -ParserStatus -Parser::parseGenericParametersBeforeWhere(SourceLoc LAngleLoc, - SmallVectorImpl &GenericParams) { - ParserStatus Result; - SyntaxParsingContext GPSContext(SyntaxContext, SyntaxKind::GenericParameterList); - bool HasNextParam; + // Parse '<'. + SourceLoc LAngleLoc = Tok.getLoc(); + builder.useLeftAngleBracket(consumeStartingLessSyntax()); + + // Parse parameters. + bool hasNext = true; do { - SyntaxParsingContext GParamContext(SyntaxContext, SyntaxKind::GenericParameter); - // Note that we're parsing a declaration. - StructureMarkerRAII ParsingDecl(*this, Tok.getLoc(), - StructureMarkerKind::Declaration); - - if (ParsingDecl.isFailed()) { - return makeParserError(); - } + ParsedGenericParameterSyntaxBuilder paramBuilder(*SyntaxContext); // Parse attributes. - DeclAttributes attributes; - if (Tok.hasComment()) - attributes.add(new (Context) RawDocCommentAttr(Tok.getCommentRange())); - parseDeclAttributeList(attributes); + // TODO: Implement syntax attribute parsing. + DeclAttributes attrsAST; + parseDeclAttributeList(attrsAST); + auto attrs = SyntaxContext->popIf(); + if (attrs) { + paramBuilder.useAttributes(std::move(*attrs)); + Generator.addDeclAttributes(attrsAST, attrsAST.getStartLoc()); + } // Parse the name of the parameter. - Identifier Name; - SourceLoc NameLoc; - if (parseIdentifier(Name, NameLoc, - diag::expected_generics_parameter_name)) { - Result.setIsParseError(); + auto ident = Context.getIdentifier(Tok.getText()); + auto name = parseIdentifierSyntax(diag::expected_generics_parameter_name); + if (!name) { + status.setIsParseError(); break; } + paramBuilder.useName(std::move(*name)); // Parse the ':' followed by a type. - SmallVector Inherited; if (Tok.is(tok::colon)) { - (void)consumeToken(); - ParserResult Ty; - + paramBuilder.useColon(consumeTokenSyntax(tok::colon)); if (Tok.isAny(tok::identifier, tok::code_complete, tok::kw_protocol, tok::kw_Any)) { - Ty = parseType(); - } else if (Tok.is(tok::kw_class)) { - diagnose(Tok, diag::unexpected_class_constraint); - diagnose(Tok, diag::suggest_anyobject) - .fixItReplace(Tok.getLoc(), "AnyObject"); - consumeToken(); - Result.setIsParseError(); + auto tyResult = parseTypeSyntax(); + status |= tyResult.getStatus(); + if (auto ty = tyResult.getOrNull()) + paramBuilder.useInheritedType(std::move(*ty)); } else { - diagnose(Tok, diag::expected_generics_type_restriction, Name); - Result.setIsParseError(); - } - - if (Ty.hasCodeCompletion()) - return makeParserCodeCompletionStatus(); + if (Tok.is(tok::kw_class)) { + diagnose(Tok, diag::unexpected_class_constraint); + diagnose(Tok, diag::suggest_anyobject) + .fixItReplace(Tok.getLoc(), "AnyObject"); + Tok.setKind(tok::identifier); + auto ty = ParsedSyntaxRecorder::makeSimpleTypeIdentifier( + consumeTokenSyntax(), None, *SyntaxContext); + paramBuilder.useInheritedType(std::move(ty)); + } else { + diagnose(Tok, diag::expected_generics_type_restriction, ident); - if (Ty.isNonNull()) - Inherited.push_back(Ty.get()); + paramBuilder.useInheritedType( + ParsedSyntaxRecorder::makeUnknownType({}, *SyntaxContext)); + } + status.setIsParseError(); + } } - // We always create generic type parameters with an invalid depth. - // Semantic analysis fills in the depth when it processes the generic - // parameter list. - auto Param = new (Context) GenericTypeParamDecl(CurDeclContext, Name, NameLoc, - GenericTypeParamDecl::InvalidDepth, - GenericParams.size()); - if (!Inherited.empty()) - Param->setInherited(Context.AllocateCopy(Inherited)); - GenericParams.push_back(Param); - - // Attach attributes. - Param->getAttrs() = attributes; - - // Add this parameter to the scope. - addToScope(Param); - - // Parse the comma, if the list continues. - HasNextParam = consumeIf(tok::comma); - } while (HasNextParam); + // Parse ',' + hasNext = Tok.is(tok::comma); + if (hasNext) + paramBuilder.useTrailingComma(consumeTokenSyntax(tok::comma)); - return Result; -} - -ParserResult -Parser::parseGenericParameters(SourceLoc LAngleLoc) { - // Parse the generic parameter list. - SmallVector GenericParams; - auto Result = parseGenericParametersBeforeWhere(LAngleLoc, GenericParams); + builder.addGenericParameterListMember(paramBuilder.build()); + } while (hasNext); - // Return early if there was code completion token. - if (Result.hasCodeCompletion()) - return Result; - auto Invalid = Result.isError(); - - // Parse the optional where-clause. - SourceLoc WhereLoc; - SmallVector Requirements; - bool FirstTypeInComplete; - if (Tok.is(tok::kw_where) && - parseGenericWhereClause(WhereLoc, Requirements, - FirstTypeInComplete).isError()) { - Invalid = true; + // Parse optional where clause. + SourceLoc whereLoc; + if (Tok.is(tok::kw_where)) { + SmallVector requirementAST; + bool FirstTypeInComplete = false; + auto where = parseGenericWhereClauseSyntax(FirstTypeInComplete); + builder.useObsoletedWhereClause(where.get()); } - + // Parse the closing '>'. - SourceLoc RAngleLoc; if (startsWithGreater(Tok)) { - RAngleLoc = consumeStartingGreater(); + builder.useRightAngleBracket(consumeStartingGreaterSyntax()); } else { - if (!Invalid) { + if (!status.isError()) { diagnose(Tok, diag::expected_rangle_generics_param); diagnose(LAngleLoc, diag::opening_angle); - Invalid = true; } // Skip until we hit the '>'. - RAngleLoc = skipUntilGreaterInTypeList(); + if (ignoreUntilGreaterInTypeList()) + builder.useRightAngleBracket(consumeStartingGreaterSyntax()); + status.setIsParseError(); } - if (GenericParams.empty()) - return nullptr; + return makeParsedResult(builder.build(), status); +} - return makeParserResult(GenericParamList::create(Context, LAngleLoc, - GenericParams, WhereLoc, - Requirements, RAngleLoc)); +ParserResult Parser::parseGenericParameters() { + auto loc = leadingTriviaLoc(); + auto syntaxResult = parseGenericParameterClauseSyntax(); + if (syntaxResult.isNull()) + return syntaxResult.getStatus(); + SyntaxContext->addSyntax(syntaxResult.get()); + + auto clause = SyntaxContext->topNode(); + if (clause.getGenericParameterList().empty()) + return nullptr; + return makeParserResult(syntaxResult.getStatus(), + Generator.generate(clause, loc)); } ParserResult Parser::maybeParseGenericParams() { if (!startsWithLess(Tok)) return nullptr; + return parseGenericParameters(); +} - if (!isInSILMode()) - return parseGenericParameters(); - - // In SIL mode, we can have multiple generic parameter lists, with the - // first one being the outmost generic parameter list. - GenericParamList *gpl = nullptr, *outer_gpl = nullptr; - do { - gpl = parseGenericParameters().getPtrOrNull(); - if (!gpl) - return nullptr; +ParserResult Parser::parseSILGenericParams() { + assert(isInSILMode()); + auto loc = leadingTriviaLoc(); + Optional result; + auto status = parseSILGenericParamsSyntax(result); + if (!result.hasValue()) { + status.setIsParseError(); + return status; + } - if (outer_gpl) - gpl->setOuterParameters(outer_gpl); - outer_gpl = gpl; - } while (startsWithLess(Tok)); - return makeParserResult(gpl); + SyntaxContext->addSyntax(std::move(*result)); + auto list = SyntaxContext->topNode(); + auto ret = Generator.generate(list, loc); + if (!ret) + return nullptr; + return makeParserResult(status, ret); } void @@ -242,131 +242,145 @@ Parser::diagnoseWhereClauseInGenericParamList(const GenericParamList * } } -/// parseGenericWhereClause - Parse a 'where' clause, which places additional -/// constraints on generic parameters or types based on them. +/// Parse a 'where' clause, which places additional constraints on generic +/// parameters or types based on them. /// /// where-clause: -/// 'where' requirement (',' requirement) * +/// 'where' generic-requirement (',' generic-requirement) * /// -/// requirement: +/// generic-requirement: /// conformance-requirement /// same-type-requirement +/// layout-requirement /// /// conformance-requirement: -/// type-identifier ':' type-identifier -/// type-identifier ':' type-composition +/// type ':' type /// /// same-type-requirement: -/// type-identifier '==' type -ParserStatus Parser::parseGenericWhereClause( - SourceLoc &WhereLoc, - SmallVectorImpl &Requirements, - bool &FirstTypeInComplete, - bool AllowLayoutConstraints) { - SyntaxParsingContext ClauseContext(SyntaxContext, - SyntaxKind::GenericWhereClause); - ParserStatus Status; - // Parse the 'where'. - WhereLoc = consumeToken(tok::kw_where); - FirstTypeInComplete = false; - SyntaxParsingContext ReqListContext(SyntaxContext, - SyntaxKind::GenericRequirementList); - bool HasNextReq; +/// type '==' type +/// +/// layout-requirement: +/// type ':' layout-constraint +ParsedSyntaxResult +Parser::parseGenericWhereClauseSyntax(bool &FirstTypeInComplete, + bool allowLayoutConstraints) { + ParsedGenericWhereClauseSyntaxBuilder builder(*SyntaxContext); + ParserStatus status; + + // Parse 'where'. + builder.useWhereKeyword(consumeTokenSyntax(tok::kw_where)); + + bool hasNext = true; do { - SyntaxParsingContext ReqContext(SyntaxContext, SyntaxContextKind::Syntax); - // Parse the leading type. It doesn't necessarily have to be just a type - // identifier if we're dealing with a same-type constraint. - ParserResult FirstType = parseType(); - - if (FirstType.hasCodeCompletion()) { - Status.setHasCodeCompletion(); - FirstTypeInComplete = true; - } - - if (FirstType.isNull()) { - Status.setIsParseError(); + auto firstType = parseTypeSyntax(); + status |= firstType.getStatus(); + FirstTypeInComplete = firstType.hasCodeCompletion(); + if (firstType.isNull()) break; - } + + ParsedGenericRequirementSyntaxBuilder elementBuilder(*SyntaxContext); if (Tok.is(tok::colon)) { - // A conformance-requirement. - SourceLoc ColonLoc = consumeToken(); - ReqContext.setCreateSyntax(SyntaxKind::ConformanceRequirement); + auto colon = consumeTokenSyntax(tok::colon); + if (Tok.is(tok::identifier) && getLayoutConstraint(Context.getIdentifier(Tok.getText()), Context) ->isKnownLayout()) { - // Parse a layout constraint. - Identifier LayoutName; - auto LayoutLoc = consumeIdentifier(&LayoutName); - auto LayoutInfo = parseLayoutConstraint(LayoutName); - if (!LayoutInfo->isKnownLayout()) { - // There was a bug in the layout constraint. - Status.setIsParseError(); - } - auto Layout = LayoutInfo; - // Types in SIL mode may contain layout constraints. - if (!AllowLayoutConstraints && !isInSILMode()) { - diagnose(LayoutLoc, + // Layout constraint. + ParsedLayoutRequirementSyntaxBuilder layoutReqBuilder(*SyntaxContext); + layoutReqBuilder.useLeftTypeIdentifier(firstType.get()); + layoutReqBuilder.useColon(std::move(colon)); + SourceLoc layoutLoc = Tok.getLoc(); + auto layout = parseLayoutConstraintSyntax(); + status |= layout.getStatus(); + + if (!allowLayoutConstraints && !isInSILMode()) + diagnose(layoutLoc, diag::layout_constraints_only_inside_specialize_attr); - } else { - // Add the layout requirement. - Requirements.push_back(RequirementRepr::getLayoutConstraint( - FirstType.get(), ColonLoc, - LayoutConstraintLoc(Layout, LayoutLoc))); - } + assert(!layout.isNull()); + layoutReqBuilder.useLayoutConstraint(layout.get()); + elementBuilder.useBody(layoutReqBuilder.build()); } else { - // Parse the protocol or composition. - ParserResult Protocol = parseType(); - - if (Protocol.isNull()) { - Status.setIsParseError(); - if (Protocol.hasCodeCompletion()) - Status.setHasCodeCompletion(); - break; - } - - // Add the requirement. - Requirements.push_back(RequirementRepr::getTypeConstraint( - FirstType.get(), ColonLoc, Protocol.get())); + // Conformance requirement. + ParsedConformanceRequirementSyntaxBuilder conformanceReqBuilder( + *SyntaxContext); + conformanceReqBuilder.useLeftTypeIdentifier(firstType.get()); + conformanceReqBuilder.useColon(std::move(colon)); + auto secondType = parseTypeSyntax(); + status |= secondType.getStatus(); + if (!secondType.isNull()) + conformanceReqBuilder.useRightTypeIdentifier(secondType.get()); + else + conformanceReqBuilder.useRightTypeIdentifier( + ParsedSyntaxRecorder::makeUnknownType({}, *SyntaxContext)); + elementBuilder.useBody(conformanceReqBuilder.build()); } } else if ((Tok.isAnyOperator() && Tok.getText() == "==") || Tok.is(tok::equal)) { - ReqContext.setCreateSyntax(SyntaxKind::SameTypeRequirement); - // A same-type-requirement + // Same type requirement. + ParsedSameTypeRequirementSyntaxBuilder sametypeReqBuilder(*SyntaxContext); + sametypeReqBuilder.useLeftTypeIdentifier(firstType.get()); if (Tok.is(tok::equal)) { diagnose(Tok, diag::requires_single_equal) - .fixItReplace(SourceRange(Tok.getLoc()), "=="); - } - SourceLoc EqualLoc = consumeToken(); - - // Parse the second type. - ParserResult SecondType = parseType(); - if (SecondType.isNull()) { - Status.setIsParseError(); - if (SecondType.hasCodeCompletion()) - Status.setHasCodeCompletion(); - break; + .fixItReplace(SourceRange(Tok.getLoc()), "=="); + ignoreToken(); + } else { + sametypeReqBuilder.useEqualityToken(consumeTokenSyntax()); } - // Add the requirement - Requirements.push_back(RequirementRepr::getSameType(FirstType.get(), - EqualLoc, - SecondType.get())); + auto secondType = parseTypeSyntax(); + status |= secondType.getStatus(); + if (!secondType.isNull()) + sametypeReqBuilder.useRightTypeIdentifier(secondType.get()); + else + sametypeReqBuilder.useRightTypeIdentifier( + ParsedSyntaxRecorder::makeUnknownType({}, *SyntaxContext)); + elementBuilder.useBody(sametypeReqBuilder.build()); } else { diagnose(Tok, diag::expected_requirement_delim); - Status.setIsParseError(); - break; + status.setIsParseError(); + + // Fallback to conformance requirement with missing right type. + ParsedConformanceRequirementSyntaxBuilder conformanceReqBuilder( + *SyntaxContext); + conformanceReqBuilder.useLeftTypeIdentifier(firstType.get()); + conformanceReqBuilder.useRightTypeIdentifier( + ParsedSyntaxRecorder::makeUnknownType({}, *SyntaxContext)); + elementBuilder.useBody(conformanceReqBuilder.build()); } - HasNextReq = consumeIf(tok::comma); - // If there's a comma, keep parsing the list. - } while (HasNextReq); - if (Requirements.empty()) - WhereLoc = SourceLoc(); + // Parse ','. + hasNext = (status.isSuccess() && Tok.is(tok::comma)); + if (hasNext) + elementBuilder.useTrailingComma(consumeTokenSyntax()); + + builder.addRequirementListMember(elementBuilder.build()); + } while (hasNext && status.isSuccess()); - return Status; + return makeParsedResult(builder.build(), status); } +ParserStatus Parser::parseGenericWhereClause( + SourceLoc &whereLoc, SmallVectorImpl &requirements, + bool &FirstTypeInComplete, bool AllowLayoutConstraints) { + auto loc = leadingTriviaLoc(); + auto syntaxResult = parseGenericWhereClauseSyntax(FirstTypeInComplete, + AllowLayoutConstraints); + if (syntaxResult.isNull()) + return syntaxResult.getStatus(); + + SyntaxContext->addSyntax(syntaxResult.get()); + auto clause = SyntaxContext->topNode(); + + whereLoc = Generator.generate(clause.getWhereKeyword(), loc); + requirements.reserve(clause.getRequirementList().size()); + for (auto elem : clause.getRequirementList()) { + if (auto req = Generator.generate(elem, loc)) + requirements.push_back(*req); + } + + return syntaxResult.getStatus(); +} /// Parse a free-standing where clause attached to a declaration, adding it to /// a generic parameter list that may (or may not) already exist. diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 7b4eaf46862a9..f6542b3da80b1 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -61,81 +61,61 @@ TypeRepr *Parser::applyAttributeToType(TypeRepr *ty, return ty; } -LayoutConstraint Parser::parseLayoutConstraint(Identifier LayoutConstraintID) { - LayoutConstraint layoutConstraint = - getLayoutConstraint(LayoutConstraintID, Context); - assert(layoutConstraint->isKnownLayout() && - "Expected layout constraint definition"); - - if (!layoutConstraint->isTrivial()) - return layoutConstraint; - - SourceLoc LParenLoc; - if (!consumeIf(tok::l_paren, LParenLoc)) { - // It is a trivial without any size constraints. - return LayoutConstraint::getLayoutConstraint(LayoutConstraintKind::Trivial, - Context); - } +/// Parse layout constraint for 'where' clause in '@_specialize' attribute +/// and in SIL. +/// +/// layout-constraint: +/// identifier +/// identifier '(' integer-literal ')' +/// identifier '(' integer-literal ',' integer-literal ')' +ParsedSyntaxResult +Parser::parseLayoutConstraintSyntax() { + assert(Tok.is(tok::identifier)); + ParsedLayoutConstraintSyntaxBuilder builder(*SyntaxContext); + + builder.useName(consumeTokenSyntax(tok::identifier)); + + if (!Tok.isFollowingLParen()) + return makeParsedResult(builder.build()); + + auto lParenLoc = Tok.getLoc(); + builder.useLeftParen(consumeTokenSyntax(tok::l_paren)); + + auto parseTrivialConstraintBody = [&]() -> bool { + int value; + + if (!Tok.is(tok::integer_literal) || + Tok.getText().getAsInteger(10, value) || value < 0) { + diagnose(Tok, diag::layout_size_should_be_positive); + return true; + } + builder.useSize(consumeTokenSyntax(tok::integer_literal)); - int size = 0; - int alignment = 0; + if (Tok.is(tok::comma)) { + builder.useComma(consumeTokenSyntax(tok::comma)); - auto ParseTrivialLayoutConstraintBody = [&] () -> bool { - // Parse the size and alignment. - if (Tok.is(tok::integer_literal)) { - if (Tok.getText().getAsInteger(10, size)) { - diagnose(Tok.getLoc(), diag::layout_size_should_be_positive); + if (!Tok.is(tok::integer_literal) || + Tok.getText().getAsInteger(10, value) || value < 0) { + diagnose(Tok, diag::layout_alignment_should_be_positive); return true; } - consumeToken(); - if (consumeIf(tok::comma)) { - // parse alignment. - if (Tok.is(tok::integer_literal)) { - if (Tok.getText().getAsInteger(10, alignment)) { - diagnose(Tok.getLoc(), diag::layout_alignment_should_be_positive); - return true; - } - consumeToken(); - } else { - diagnose(Tok.getLoc(), diag::layout_alignment_should_be_positive); - return true; - } - } - } else { - diagnose(Tok.getLoc(), diag::layout_size_should_be_positive); - return true; + builder.useAlignment(consumeTokenSyntax(tok::integer_literal)); } return false; }; - if (ParseTrivialLayoutConstraintBody()) { - // There was an error during parsing. - skipUntil(tok::r_paren); - consumeIf(tok::r_paren); - return LayoutConstraint::getUnknownLayout(); - } - - if (!consumeIf(tok::r_paren)) { - // Expected a closing r_paren. - diagnose(Tok.getLoc(), diag::expected_rparen_layout_constraint); - consumeToken(); - return LayoutConstraint::getUnknownLayout(); - } - - if (size < 0) { - diagnose(Tok.getLoc(), diag::layout_size_should_be_positive); - return LayoutConstraint::getUnknownLayout(); - } - - if (alignment < 0) { - diagnose(Tok.getLoc(), diag::layout_alignment_should_be_positive); - return LayoutConstraint::getUnknownLayout(); + if (parseTrivialConstraintBody()) { + ignoreUntil(tok::r_paren); + if (Tok.is(tok::r_paren)) + builder.useRightParen(consumeTokenSyntax(tok::r_paren)); + } else { + auto rParen = parseMatchingTokenSyntax(tok::r_paren, + diag::expected_rparen_layout_constraint, + lParenLoc); + if (rParen) + builder.useRightParen(std::move(*rParen)); } - - // Otherwise it is a trivial layout constraint with - // provided size and alignment. - return LayoutConstraint::getLayoutConstraint(layoutConstraint->getKind(), size, - alignment, Context); + return makeParsedResult(builder.build()); } /// parseTypeSimple @@ -369,7 +349,7 @@ Parser::TypeASTResult Parser::parseType(Diag<> MessageID, // the function body; otherwise, they are visible when parsing the type. if (!IsSILFuncDecl) GenericsScope.emplace(this, ScopeKind::Generics); - generics = maybeParseGenericParams().getPtrOrNull(); + generics = parseSILGenericParams().getPtrOrNull(); } // In SIL mode, parse box types { ... }. diff --git a/lib/Parse/ParsedSyntaxBuilders.cpp.gyb b/lib/Parse/ParsedSyntaxBuilders.cpp.gyb index 9ab3964f2b2cb..9306c0c8902f1 100644 --- a/lib/Parse/ParsedSyntaxBuilders.cpp.gyb +++ b/lib/Parse/ParsedSyntaxBuilders.cpp.gyb @@ -26,7 +26,7 @@ using namespace swift; using namespace swift::syntax; -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.is_buildable(): % for child in node.children: % child_elt = None diff --git a/lib/Parse/ParsedSyntaxNodes.cpp.gyb b/lib/Parse/ParsedSyntaxNodes.cpp.gyb index e3bb56c91812e..a21a0674a39e1 100644 --- a/lib/Parse/ParsedSyntaxNodes.cpp.gyb +++ b/lib/Parse/ParsedSyntaxNodes.cpp.gyb @@ -23,7 +23,7 @@ using namespace swift; using namespace swift::syntax; -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % for child in node.children: % if child.is_optional: Optional diff --git a/lib/Parse/ParsedSyntaxRecorder.cpp.gyb b/lib/Parse/ParsedSyntaxRecorder.cpp.gyb index b305e25e7cc8f..1e62ea13ba721 100644 --- a/lib/Parse/ParsedSyntaxRecorder.cpp.gyb +++ b/lib/Parse/ParsedSyntaxRecorder.cpp.gyb @@ -29,7 +29,7 @@ bool ParsedSyntaxRecorder::formExactLayoutFor(syntax::SyntaxKind Kind, MutableArrayRef Elements, function_ref)> receiver) { switch (Kind) { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: case SyntaxKind::${node.syntax_kind}: { % if node.children: % child_count = len(node.children) @@ -77,7 +77,7 @@ bool ParsedSyntaxRecorder::formExactLayoutFor(syntax::SyntaxKind Kind, } } -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.children: % child_params = [] % child_move_args = [] diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index f25a65fa096ef..7980fd39f1006 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -527,7 +527,7 @@ Parser::Parser(std::unique_ptr Lex, SourceFile &SF, L->getBufferID(), SF.SyntaxParsingCache, SF.getASTContext().getSyntaxArena())))), - Generator(SF.getASTContext(), &State) { + Generator(SF.getASTContext(), *this) { State = PersistentState; if (!State) { OwnedState.reset(new PersistentParserState()); diff --git a/lib/ParseSIL/ParseSIL.cpp b/lib/ParseSIL/ParseSIL.cpp index cededafc650aa..5915ef23758e6 100644 --- a/lib/ParseSIL/ParseSIL.cpp +++ b/lib/ParseSIL/ParseSIL.cpp @@ -3115,7 +3115,7 @@ bool SILParser::parseSILInstruction(SILBuilder &B) { SmallVector operandTypes; { Scope genericsScope(&P, ScopeKind::Generics); - generics = P.maybeParseGenericParams().getPtrOrNull(); + generics = P.parseSILGenericParams().getPtrOrNull(); patternEnv = handleSILGenericParams(P.Context, generics, &P.SF); if (P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "(")) @@ -5720,7 +5720,7 @@ bool SILParserTUState::parseSILProperty(Parser &P) { GenericEnvironment *patternEnv; Scope toplevelScope(&P, ScopeKind::TopLevel); Scope genericsScope(&P, ScopeKind::Generics); - generics = P.maybeParseGenericParams().getPtrOrNull(); + generics = P.parseSILGenericParams().getPtrOrNull(); patternEnv = handleSILGenericParams(P.Context, generics, &P.SF); if (patternEnv) { @@ -6033,7 +6033,7 @@ Optional SILParser::parseProtocolConformance( // Make sure we don't leave it uninitialized in the caller genericEnv = nullptr; - auto *genericParams = P.maybeParseGenericParams().getPtrOrNull(); + auto *genericParams = P.parseSILGenericParams().getPtrOrNull(); if (genericParams) { genericEnv = handleSILGenericParams(P.Context, genericParams, &P.SF); } diff --git a/lib/Syntax/SyntaxBuilders.cpp.gyb b/lib/Syntax/SyntaxBuilders.cpp.gyb index 8c93726dc5123..3a3af38751078 100644 --- a/lib/Syntax/SyntaxBuilders.cpp.gyb +++ b/lib/Syntax/SyntaxBuilders.cpp.gyb @@ -25,7 +25,7 @@ using namespace swift; using namespace swift::syntax; -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.is_buildable(): % for child in node.children: ${node.name}Builder & diff --git a/lib/Syntax/SyntaxFactory.cpp.gyb b/lib/Syntax/SyntaxFactory.cpp.gyb index dc6ad1a8c90dd..f7652bd83b5f8 100644 --- a/lib/Syntax/SyntaxFactory.cpp.gyb +++ b/lib/Syntax/SyntaxFactory.cpp.gyb @@ -63,7 +63,7 @@ SyntaxFactory::makeUnknownSyntax(llvm::ArrayRef Tokens, Syntax SyntaxFactory::makeBlankCollectionSyntax(SyntaxKind Kind) { switch(Kind) { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.is_syntax_collection(): case SyntaxKind::${node.syntax_kind}: return makeBlank${node.syntax_kind}(); % end @@ -76,7 +76,7 @@ Syntax SyntaxFactory::makeBlankCollectionSyntax(SyntaxKind Kind) { std::pair SyntaxFactory::countChildren(SyntaxKind Kind){ switch(Kind) { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if not node.is_syntax_collection(): case SyntaxKind::${node.syntax_kind}: % child_count = len(node.children) @@ -92,7 +92,7 @@ SyntaxFactory::countChildren(SyntaxKind Kind){ bool SyntaxFactory::canServeAsCollectionMemberRaw(SyntaxKind CollectionKind, SyntaxKind MemberKind) { switch (CollectionKind) { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.is_syntax_collection(): case SyntaxKind::${node.syntax_kind}: % if node.collection_element_choices: @@ -125,7 +125,7 @@ RC SyntaxFactory::createRaw(SyntaxKind Kind, llvm::ArrayRef> Elements, RC Arena) { switch (Kind) { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: case SyntaxKind::${node.syntax_kind}: { % if node.children: % child_count = len(node.children) @@ -178,7 +178,7 @@ Optional SyntaxFactory::createSyntax(SyntaxKind Kind, return None; } -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.children: % child_params = [] % for child in node.children: diff --git a/lib/Syntax/SyntaxKind.cpp.gyb b/lib/Syntax/SyntaxKind.cpp.gyb index 7603508970385..811c02ba3b14c 100644 --- a/lib/Syntax/SyntaxKind.cpp.gyb +++ b/lib/Syntax/SyntaxKind.cpp.gyb @@ -52,7 +52,7 @@ bool isTokenKeyword(tok kind) { bool parserShallOmitWhenNoChildren(syntax::SyntaxKind Kind) { switch(Kind) { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.shall_be_omitted_when_empty(): case syntax::SyntaxKind::${node.syntax_kind}: % end @@ -73,7 +73,7 @@ void dumpSyntaxKind(llvm::raw_ostream &os, const SyntaxKind kind) { case SyntaxKind::Unknown: os << "Unknown"; break; -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: case SyntaxKind::${node.syntax_kind}: os << "${node.syntax_kind}"; break; @@ -83,7 +83,7 @@ void dumpSyntaxKind(llvm::raw_ostream &os, const SyntaxKind kind) { bool isCollectionKind(SyntaxKind Kind) { switch(Kind) { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.is_syntax_collection(): case SyntaxKind::${node.syntax_kind}: % end @@ -147,7 +147,7 @@ SyntaxKind getUnknownKind(SyntaxKind Kind) { llvm::raw_ostream &llvm::operator<<(llvm::raw_ostream &OS, swift::syntax::SyntaxKind Kind) { switch (Kind) { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: case swift::syntax::SyntaxKind::${node.syntax_kind}: OS << "${node.syntax_kind}"; break; diff --git a/lib/Syntax/SyntaxNodes.cpp.gyb b/lib/Syntax/SyntaxNodes.cpp.gyb index 34418e182f1ca..e3302f3389914 100644 --- a/lib/Syntax/SyntaxNodes.cpp.gyb +++ b/lib/Syntax/SyntaxNodes.cpp.gyb @@ -24,7 +24,7 @@ using namespace swift; using namespace swift::syntax; -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.requires_validation(): void ${node.name}::validate() const { #ifndef NDEBUG diff --git a/lib/Syntax/SyntaxVisitor.cpp.gyb b/lib/Syntax/SyntaxVisitor.cpp.gyb index 722ab5d46f4e7..14e92d72c1995 100644 --- a/lib/Syntax/SyntaxVisitor.cpp.gyb +++ b/lib/Syntax/SyntaxVisitor.cpp.gyb @@ -21,7 +21,7 @@ #include "swift/Syntax/SyntaxVisitor.h" #include "swift/Basic/Defer.h" -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if is_visitable(node): void swift::syntax::SyntaxVisitor::visit(${node.name} node) { visitChildren(node); @@ -36,7 +36,7 @@ void swift::syntax::SyntaxVisitor::visit(Syntax node) { case SyntaxKind::Token: visit(node.castTo()); return; -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if is_visitable(node): case SyntaxKind::${node.syntax_kind}: visit(node.castTo<${node.name}>()); diff --git a/test/Parse/invalid.swift b/test/Parse/invalid.swift index 7a290d5c8b669..097588b54f695 100644 --- a/test/Parse/invalid.swift +++ b/test/Parse/invalid.swift @@ -124,7 +124,7 @@ prefix func %(x: T) -> T { return x } // No error expected - the < is conside struct Weak { // expected-error {{'class' constraint can only appear on protocol declarations}} // expected-note@-1 {{did you mean to write an 'AnyObject' constraint?}} {{16-21=AnyObject}} - weak let value: T // expected-error {{'weak' must be a mutable variable, because it may change at runtime}} expected-error {{'weak' variable should have optional type 'T?'}} expected-error {{'weak' must not be applied to non-class-bound 'T'; consider adding a protocol conformance that has a class bound}} + weak let value: T // expected-error {{'weak' must be a mutable variable, because it may change at runtime}} expected-error {{'weak' variable should have optional type 'T?'}} } let x: () = () diff --git a/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds b/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds index 6a687bae4e8c9..680d7b2d4cae4 100644 --- a/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds +++ b/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds @@ -121,7 +121,7 @@ protocol PP { associatedtype B: Sequence associatedtype C = Int associatedtype D: Sequence = [Int] - associatedtype E: Sequence = [[Int]] where A.Element : Sequence + associatedtype E: Sequence = [[Int]] where A.Element : Sequence private associatedtype F @objc associatedtype G } @@ -155,7 +155,7 @@ class Bar: Foo foo: Int = 42 } -class C<A, B> where A: Foo, B == Bar {} +class C<A, B> where A: Foo, B == Bar {} @available(*, unavailable) private class C {} @@ -183,9 +183,9 @@ struct foo { } } -struct S<A, B, C, @objc D> where A:B, B==C, A : C, B.C == D.A, A.B: C.D {} +struct S<A, B, C, @objc D> where A:B, B==C, A : C, B.C == D.A, A.B: C.D {} -private struct S<A, B>: Base where A: B { +private struct S<A, B>: Base where A: B { private struct S: A, B {} } @@ -205,18 +205,18 @@ func foo( a: { @objc @available(*, unavailable) -private static override func foo<a, b, c>(a b: Int, c: Int) throws -> [Int] where a==p1, b:p2 { ddd } +private static override func foo<a, b, c>(a b: Int, c: Int) throws -> [Int] where a==p1, b:p2 { ddd } func rootView() -> Label {} static func ==() -> bool {} static func !=<a, b, c>() -> bool {} } @objc -private protocol foo : bar where A==B {} +private protocol foo : bar where A==B {} protocol foo { func foo() } private protocol foo{} @objc -public protocol foo where A:B {} +public protocol foo where A:B {} #if blah func tryfoo() { @@ -431,7 +431,7 @@ fileprivate extension ext ext : extProtocol {} -extension ext where A == Int, B: Numeric {} +extension ext where A == Int, B: Numeric {} extension ext.a.b {} @@ -478,7 +478,7 @@ enum E1 : String bar = "test", baz(x: Int, String) = 12 indirect case qux(E1) - indirect private enum E2<T>: String where T: SomeProtocol { + indirect private enum E2<T>: String where T: SomeProtocol { case foo, bar, baz } } @@ -507,8 +507,8 @@ func higherOrderFunc() #available(iOS 11, macOS 10.11.2, *) {} -@_specialize(where T == Int) -@_specialize(exported: true, where T == String) +@_specialize(where T == Int) +@_specialize(exported: true, where T == String) public func specializedGenericFunc<T>(_ t: T) -> T { return t } diff --git a/unittests/Syntax/DeclSyntaxTests.cpp b/unittests/Syntax/DeclSyntaxTests.cpp index 5f29d564442fa..bc13978633314 100644 --- a/unittests/Syntax/DeclSyntaxTests.cpp +++ b/unittests/Syntax/DeclSyntaxTests.cpp @@ -550,11 +550,11 @@ GenericWhereClauseSyntax getCannedWhereClause() { auto T = SyntaxFactory::makeTypeIdentifier("T", {}, Trivia::spaces(1)); auto EqualEqual = SyntaxFactory::makeEqualityOperator({}, Trivia::spaces(1)); auto Int = SyntaxFactory::makeTypeIdentifier("Int", {}, Trivia::spaces(1)); - auto SameType = SyntaxFactory::makeSameTypeRequirement(T, EqualEqual, Int, - None); + auto SameType = SyntaxFactory::makeSameTypeRequirement(T, EqualEqual, Int); + auto Req = SyntaxFactory::makeGenericRequirement(SameType, None); auto Requirements = SyntaxFactory::makeBlankGenericRequirementList() - .appending(SameType); + .appending(Req); return SyntaxFactory::makeBlankGenericWhereClause() .withWhereKeyword(WhereKW) diff --git a/utils/gyb_syntax_support/GenericNodes.py b/utils/gyb_syntax_support/GenericNodes.py index e93a80b3bfe05..afb6a4af2e99d 100644 --- a/utils/gyb_syntax_support/GenericNodes.py +++ b/utils/gyb_syntax_support/GenericNodes.py @@ -11,22 +11,39 @@ ]), Node('GenericRequirementList', kind='SyntaxCollection', - element='Syntax', + element='GenericRequirement', element_name='GenericRequirement'), + # generic-requirement -> + # (same-type-requrement|conformance-requirement|layout-requirement) ','? + Node('GenericRequirement', kind='Syntax', + traits=['WithTrailingComma'], + children=[ + Child('Body', kind='Syntax', + node_choices=[ + Child('SameTypeRequirement', + kind='SameTypeRequirement'), + Child('ConformanceRequirement', + kind='ConformanceRequirement'), + Child('LayoutRequirement', + kind='LayoutRequirement'), + ]), + Child('TrailingComma', kind='CommaToken', + is_optional=True), + ]), + # same-type-requirement -> type-identifier == type Node('SameTypeRequirement', kind='Syntax', - traits=['WithTrailingComma'], children=[ Child('LeftTypeIdentifier', kind='Type'), Child('EqualityToken', kind='Token', token_choices=[ 'SpacedBinaryOperatorToken', 'UnspacedBinaryOperatorToken', + 'PrefixOperatorToken', + 'PostfixOperatorToken', ]), Child('RightTypeIdentifier', kind='Type'), - Child('TrailingComma', kind='CommaToken', - is_optional=True), ]), Node('GenericParameterList', kind='SyntaxCollection', @@ -55,17 +72,41 @@ Child('LeftAngleBracket', kind='LeftAngleToken'), Child('GenericParameterList', kind='GenericParameterList', collection_element_name='GenericParameter'), + Child('ObsoletedWhereClause', kind='GenericWhereClause', + is_optional=True), Child('RightAngleBracket', kind='RightAngleToken'), ]), # conformance-requirement -> type-identifier : type-identifier Node('ConformanceRequirement', kind='Syntax', - traits=['WithTrailingComma'], children=[ Child('LeftTypeIdentifier', kind='Type'), Child('Colon', kind='ColonToken'), Child('RightTypeIdentifier', kind='Type'), - Child('TrailingComma', kind='CommaToken', - is_optional=True), + ]), + + # layout-requirement -> type ':' layout-constraint + Node('LayoutRequirement', kind='Syntax', + children=[ + Child('LeftTypeIdentifier', kind='Type'), + Child('Colon', kind='ColonToken'), + Child('LayoutConstraint', kind='LayoutConstraint'), + ]), + + # layout-constraint -> + # identifier ('(' integer-literal (',' integer-literal)? ')')? + Node('LayoutConstraint', kind='Syntax', + children=[ + Child('Name', kind='IdentifierToken'), + Child('LeftParen', kind='LeftParenToken', + is_optional=True), + Child('Size', kind='IntegerLiteralToken', + is_optional=True), + Child('Comma', kind='CommaToken', + is_optional=True), + Child('Alignment', kind='IntegerLiteralToken', + is_optional=True), + Child('RightParen', kind='RightParenToken', + is_optional=True), ]), ] diff --git a/utils/gyb_syntax_support/NodeSerializationCodes.py b/utils/gyb_syntax_support/NodeSerializationCodes.py index 4bacc660f7cbc..fb9edd7ca3e40 100644 --- a/utils/gyb_syntax_support/NodeSerializationCodes.py +++ b/utils/gyb_syntax_support/NodeSerializationCodes.py @@ -233,6 +233,9 @@ 'PoundAssertStmt': 229, 'SomeType': 230, 'CustomAttribute': 231, + 'GenericRequirement': 232, + 'LayoutRequirement': 233, + 'LayoutConstraint': 234, } diff --git a/utils/gyb_syntax_support/SILOnlyNodes.py b/utils/gyb_syntax_support/SILOnlyNodes.py new file mode 100644 index 0000000000000..799ca5c99ee56 --- /dev/null +++ b/utils/gyb_syntax_support/SILOnlyNodes.py @@ -0,0 +1,9 @@ +from Node import Node # noqa: I201 + +# These nodes are used only in SIL parsing. + +SILONLY_NODES = [ + # generic-parameter-clause-list + Node('GenericParameterClauseList', kind='SyntaxCollection', + element='GenericParameterClause'), +] diff --git a/utils/gyb_syntax_support/__init__.py b/utils/gyb_syntax_support/__init__.py index 6f32da7920fa7..437ce147b321c 100644 --- a/utils/gyb_syntax_support/__init__.py +++ b/utils/gyb_syntax_support/__init__.py @@ -11,6 +11,7 @@ verify_syntax_node_serialization_codes from PatternNodes import PATTERN_NODES # noqa: I201 +from SILOnlyNodes import SILONLY_NODES # noqa: I201 from StmtNodes import STMT_NODES # noqa: I201 import Token from Trivia import TRIVIAS # noqa: I201 From b40509b643ff21bd0cfe6543e571f48f1d6619ee Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Fri, 20 Sep 2019 09:08:19 -0700 Subject: [PATCH 104/199] Update README.md Split out the TensorFlow CI entries. They were previously marked with a TensorFlow suffix, which obscured them in the rest of the community CI. This makes them easier to find. --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 98f49b0741e50..23feec3424e8b 100644 --- a/README.md +++ b/README.md @@ -18,12 +18,16 @@ |**[Ubuntu 16.04 ](https://github.com/apple/swift-community-hosted-continuous-integration/blob/master/nodes/aarch64_ubuntu_16.04.json)** | AArch64 |[![Build Status](https://ci-external.swift.org/job/oss-swift-RA-linux-ubuntu-16.04-aarch64/lastCompletedBuild/badge/icon)](https://ci-external.swift.org/job/oss-swift-RA-linux-ubuntu-16.04-aarch64)| |**[Android](https://github.com/apple/swift-community-hosted-continuous-integration/blob/master/nodes/x86_64_ubuntu_16_04_LTS_android.json)** | ARMv7 |[![Build Status](https://ci-external.swift.org/job/oss-swift-RA-linux-ubuntu-16.04-android/lastCompletedBuild/badge/icon)](https://ci-external.swift.org/job/oss-swift-RA-linux-ubuntu-16.04-android)| |**[Android](https://github.com/apple/swift-community-hosted-continuous-integration/blob/master/nodes/x86_64_ubuntu_16_04_LTS_android.json)** | AArch64 |[![Build Status](https://ci-external.swift.org/job/oss-swift-RA-linux-ubuntu-16.04-android-arm64/lastCompletedBuild/badge/icon)](https://ci-external.swift.org/job/oss-swift-RA-linux-ubuntu-16.04-android-arm64)| -|**[Ubuntu 16.04 (TensorFlow)](https://github.com/apple/swift-community-hosted-continuous-integration/blob/master/nodes/x86_64_ubuntu_16_04_tensorflow.json)** | x86_64 |[![Build Status](https://ci-external.swift.org/job/oss-swift-RA-linux-ubuntu-16.04-tensorflow/lastCompletedBuild/badge/icon)](https://ci-external.swift.org/job/oss-swift-RA-linux-ubuntu-16.04-tensorflow)| -|**[macOS 10.13 (TensorFlow)](https://github.com/apple/swift-community-hosted-continuous-integration/blob/master/nodes/x86_64_macos_high_sierra_tensorflow.json)** | x86_64 |[![Build Status](https://ci-external.swift.org/job/oss-swift-RA-macOS-tensorflow/lastCompletedBuild/badge/icon)](https://ci-external.swift.org/job/oss-swift-RA-macOS-tensorflow)| -|**[Ubuntu 16.04 (TensorFlow with GPU)](https://github.com/apple/swift-community-hosted-continuous-integration/blob/master/nodes/x86_64_ubuntu_16_04_tensorflow_gpu.json)** | x86_64 |[![Build Status](https://ci-external.swift.org/job/oss-swift-RA-linux-ubuntu-16.04-tensorflow-gpu/lastCompletedBuild/badge/icon)](https://ci-external.swift.org/job/oss-swift-RA-linux-ubuntu-16.04-tensorflow-gpu)| |**[Debian 9.5](https://github.com/apple/swift-community-hosted-continuous-integration/blob/master/nodes/x86_64_debian_9.5.json)** | x86_64 | [![Build Status](https://ci-external.swift.org/job/oss-swift-RA-linux-debian-9_5/lastCompletedBuild/badge/icon)](https://ci-external.swift.org/job/oss-swift-RA-linux-debian-9_5)| |**[Windows 2019](https://github.com/apple/swift-community-hosted-continuous-integration/blob/master/nodes/x86_64_windows_2019.json)** | x86_64 | [![Build Status](https://ci-external.swift.org/job/oss-swift-windows-x86_64/lastCompletedBuild/badge/icon)](https://ci-external.swift.org/job/oss-swift-windows-x86_64)| +**Swift TensorFlow Community-Hosted CI Platforms** + +| **OS** | **Architecture** | **Build** | +|---|:---:|:---:| +|**[Ubuntu 16.04](https://github.com/apple/swift-community-hosted-continuous-integration/blob/master/nodes/x86_64_ubuntu_16_04_tensorflow.json)** | x86_64 |[![Build Status](https://ci-external.swift.org/job/oss-swift-RA-linux-ubuntu-16.04-tensorflow/lastCompletedBuild/badge/icon)](https://ci-external.swift.org/job/oss-swift-RA-linux-ubuntu-16.04-tensorflow)| +|**[macOS 10.13](https://github.com/apple/swift-community-hosted-continuous-integration/blob/master/nodes/x86_64_macos_high_sierra_tensorflow.json)** | x86_64 |[![Build Status](https://ci-external.swift.org/job/oss-swift-RA-macOS-tensorflow/lastCompletedBuild/badge/icon)](https://ci-external.swift.org/job/oss-swift-RA-macOS-tensorflow)| +|**[Ubuntu 16.04 (GPU)](https://github.com/apple/swift-community-hosted-continuous-integration/blob/master/nodes/x86_64_ubuntu_16_04_tensorflow_gpu.json)** | x86_64 |[![Build Status](https://ci-external.swift.org/job/oss-swift-RA-linux-ubuntu-16.04-tensorflow-gpu/lastCompletedBuild/badge/icon)](https://ci-external.swift.org/job/oss-swift-RA-linux-ubuntu-16.04-tensorflow-gpu)| ## Welcome to Swift From ba3a3a7561f1f7ce43dd9e8f884b8368e510beeb Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Fri, 20 Sep 2019 11:11:19 -0700 Subject: [PATCH 105/199] build: try harder to pass along CMAKE_Swift_COMPILER This is needed for the CMake 3.15 based build. --- utils/build-script-impl | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/build-script-impl b/utils/build-script-impl index ec6e334583292..070797cff9c4f 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -2779,6 +2779,7 @@ for host in "${ALL_HOSTS[@]}"; do -DCMAKE_C_COMPILER:PATH="${LLVM_BIN}/clang" -DCMAKE_CXX_COMPILER:PATH="${LLVM_BIN}/clang++" -DCMAKE_SWIFT_COMPILER:PATH="${SWIFTC_BIN}" + -DCMAKE_Swift_COMPILER:PATH="${SWIFTC_BIN}" -DCMAKE_INSTALL_PREFIX:PATH="$(get_host_install_prefix ${host})" -DCMAKE_INSTALL_LIBDIR:PATH="lib" From 22f580e5c66f73e26733fd6617ccae4aea00f25d Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Fri, 20 Sep 2019 11:34:57 -0700 Subject: [PATCH 106/199] [polymorphic-builtin] Fix ASAN error. --- lib/SILOptimizer/Utils/ConstantFolding.cpp | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/lib/SILOptimizer/Utils/ConstantFolding.cpp b/lib/SILOptimizer/Utils/ConstantFolding.cpp index a453e4b73cc0c..0e101edc22d61 100644 --- a/lib/SILOptimizer/Utils/ConstantFolding.cpp +++ b/lib/SILOptimizer/Utils/ConstantFolding.cpp @@ -584,8 +584,7 @@ constantFoldAndCheckDivision(BuiltinInst *BI, BuiltinValueKind ID, } static SILValue specializePolymorphicBuiltin(BuiltinInst *bi, - BuiltinValueKind id, - Optional &resultsInError) { + BuiltinValueKind id) { // If we are not a polymorphic builtin, return an empty SILValue() // so we keep on scanning. if (!isPolymorphicBuiltin(id)) @@ -1831,11 +1830,7 @@ ConstantFolder::processWorkList() { if (auto *bi = dyn_cast(I)) { if (auto kind = bi->getBuiltinKind()) { - Optional ResultsInError; - if (EnableDiagnostics) - ResultsInError = false; - if (SILValue v = specializePolymorphicBuiltin(bi, kind.getValue(), - ResultsInError)) { + if (SILValue v = specializePolymorphicBuiltin(bi, kind.getValue())) { // If bi had a result, RAUW. if (bi->getResult(0)->getType() != bi->getModule().Types.getEmptyTupleType()) @@ -1843,12 +1838,8 @@ ConstantFolder::processWorkList() { // Then delete no matter what. bi->eraseFromParent(); InvalidateInstructions = true; + continue; } - - // If we did not pass in a None and the optional is set to true, add the - // user to our error set. - if (ResultsInError.hasValue() && ResultsInError.getValue()) - ErrorSet.insert(bi); } } From 5189daafd375db2ec6bdc185e0a385f60f68aeb2 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 19 Sep 2019 16:51:06 -0400 Subject: [PATCH 107/199] Add a couple of crashing test cases --- .../compiler_crashers_2/0207-sr7371.swift | 36 ++++++++++++ .../compiler_crashers_2/0208-sr8751.swift | 58 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 validation-test/compiler_crashers_2/0207-sr7371.swift create mode 100644 validation-test/compiler_crashers_2/0208-sr8751.swift diff --git a/validation-test/compiler_crashers_2/0207-sr7371.swift b/validation-test/compiler_crashers_2/0207-sr7371.swift new file mode 100644 index 0000000000000..1dd2d54f693ad --- /dev/null +++ b/validation-test/compiler_crashers_2/0207-sr7371.swift @@ -0,0 +1,36 @@ +// RUN: not --crash %target-swift-frontend -emit-ir %s + +public protocol TypedParserResultTransferType { + // Remove type constraint + associatedtype Result: ParserResult +} + +public struct AnyTypedParserResultTransferType: TypedParserResultTransferType { + public typealias Result = P + // Remove property + public let result: P +} + +public protocol ParserResult {} +public protocol StaticParser: ParserResult {} + +// Change comformance to ParserResult +public protocol TypedStaticParser: StaticParser { + // Remove type constraint + associatedtype ResultTransferType: TypedParserResultTransferType +} + +// Remove where clause +public protocol MutableSelfStaticParser: TypedStaticParser where ResultTransferType == AnyTypedParserResultTransferType { + func parseTypeVar() -> AnyTypedParserResultTransferType +} + +extension MutableSelfStaticParser { + + public func anyFunction() -> () { + let t = self.parseTypeVar + // Remove this and below + _ = t() + _ = self.parseTypeVar() + } +} diff --git a/validation-test/compiler_crashers_2/0208-sr8751.swift b/validation-test/compiler_crashers_2/0208-sr8751.swift new file mode 100644 index 0000000000000..e0018a74d0235 --- /dev/null +++ b/validation-test/compiler_crashers_2/0208-sr8751.swift @@ -0,0 +1,58 @@ +// RUN: not --crash %target-swift-frontend -emit-ir %s + +protocol TreeProtocol { + + typealias NodeProtocol = _TreeNodeProtocol + associatedtype Node : NodeProtocol where Node.Tree == Self + associatedtype NValuesTraversedBreadthFirst : Sequence = FooVals where NValuesTraversedBreadthFirst.Iterator.Element == Node.Val + + var root: Node? { get } + +} + +protocol _TreeNodeProtocol { + + associatedtype Tree : TreeProtocol where Tree.Node == Self + associatedtype Val + + var value: Val { get } + var children: [Tree.Node] { get } + +} + +struct Foo : TreeProtocol { + + struct Node : _TreeNodeProtocol { + typealias Tree = Foo + typealias Val = V + + var value: Val { + fatalError() + } + var children: [Tree.Node] { + fatalError() + } + } + + var root: Foo.Node? { + fatalError() + } + +} + +struct FooVals : Sequence { + + struct Iterator : IteratorProtocol { + + typealias Element = F.Node.Val + + mutating func next() -> F.Node.Val? { + fatalError() + } + } + + func makeIterator() -> FooVals.Iterator { + fatalError() + } + +} From 72b61f55bf8f69e69961030d6c2b83c45338c82c Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 10 Sep 2019 13:17:37 -0700 Subject: [PATCH 108/199] [Diagnostics] Tailored diagnostic for "condition" expression Since all condition expressions supposed to be convertible to `Bool`, let's use that type as contextual and produce a tailored diagnostic. --- include/swift/AST/DiagnosticsSema.def | 6 ++++ lib/Sema/CSDiagnostics.cpp | 6 ++++ lib/Sema/TypeCheckConstraints.cpp | 30 ++++--------------- lib/Sema/TypeChecker.h | 2 ++ test/Constraints/diagnostics.swift | 4 +-- .../invalid_logicvalue_coercion.swift | 4 +-- test/Misc/misc_diagnostics.swift | 4 +-- test/Parse/switch.swift | 4 +-- test/Sema/pound_assert.swift | 4 +-- test/expr/expressions.swift | 10 +++---- test/stmt/if_while_var.swift | 2 +- test/stmt/statements.swift | 11 +++---- 12 files changed, 42 insertions(+), 45 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 15e1b8143253d..2d61e8109a3cb 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -396,6 +396,12 @@ ERROR(cannot_convert_partial_argument_value_protocol,none, ERROR(cannot_convert_argument_value_nil,none, "'nil' is not compatible with expected argument type %0", (Type)) +ERROR(cannot_convert_condition_value,none, + "cannot convert value of type %0 to expected condition type %1", + (Type, Type)) +ERROR(cannot_convert_condition_value_nil,none, + "'nil' is not compatible with expected condition type %0", (Type)) + ERROR(cannot_yield_rvalue_by_reference_same_type,none, "cannot yield immutable value of type %0 as an inout yield", (Type)) ERROR(cannot_yield_rvalue_by_reference,none, diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 4f44989f0ceb5..826a526f7168a 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -692,6 +692,8 @@ Optional> GenericArgumentsMismatchFailure::getDiagnosticFor( return diag::cannot_convert_coerce; case CTP_SubscriptAssignSource: return diag::cannot_convert_subscript_assign; + case CTP_Condition: + return diag::cannot_convert_condition_value; case CTP_ThrowStmt: case CTP_Unused: @@ -1954,6 +1956,8 @@ getContextualNilDiagnostic(ContextualTypePurpose CTP) { return diag::cannot_convert_assign_nil; case CTP_SubscriptAssignSource: return diag::cannot_convert_subscript_assign_nil; + case CTP_Condition: + return diag::cannot_convert_condition_value_nil; } llvm_unreachable("Unhandled ContextualTypePurpose in switch"); } @@ -2691,6 +2695,8 @@ ContextualFailure::getDiagnosticFor(ContextualTypePurpose context, case CTP_SubscriptAssignSource: return forProtocol ? diag::cannot_convert_subscript_assign_protocol : diag::cannot_convert_subscript_assign; + case CTP_Condition: + return diag::cannot_convert_condition_value; case CTP_ThrowStmt: case CTP_Unused: diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 74d1e7c880e82..26afc14d8854d 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -3009,31 +3009,13 @@ bool TypeChecker::typeCheckCondition(Expr *&expr, DeclContext *dc) { return !resultTy; } - /// Expression type checking listener for conditions. - class ConditionListener : public ExprTypeCheckListener { - Expr *OrigExpr = nullptr; - - public: - // Add the appropriate Boolean constraint. - bool builtConstraints(ConstraintSystem &cs, Expr *expr) override { - // Save the original expression. - OrigExpr = expr; - - // Otherwise, the result must be convertible to Bool. - auto boolDecl = cs.getASTContext().getBoolDecl(); - if (!boolDecl) - return true; - - // Condition must convert to Bool. - cs.addConstraint(ConstraintKind::Conversion, cs.getType(expr), - boolDecl->getDeclaredType(), - cs.getConstraintLocator(expr)); - return false; - } - }; + auto *boolDecl = Context.getBoolDecl(); + if (!boolDecl) + return true; - ConditionListener listener; - auto resultTy = typeCheckExpression(expr, dc, &listener); + auto resultTy = typeCheckExpression( + expr, dc, TypeLoc::withoutLoc(boolDecl->getDeclaredType()), + CTP_Condition); return !resultTy; } diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 7083a84097486..b413397f83118 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -219,6 +219,8 @@ enum ContextualTypePurpose { CTP_AssignSource, ///< AssignExpr source operand coerced to result type. CTP_SubscriptAssignSource, ///< AssignExpr source operand coerced to subscript ///< result type. + CTP_Condition, ///< Condition expression of various statements e.g. + ///< `if`, `for`, `while` etc. CTP_CannotFail, ///< Conversion can never fail. abort() if it does. }; diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index bc76267222193..b97a6b91dfac4 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -188,10 +188,10 @@ func r17224804(_ monthNumber : Int) { // QoI: Operand of postfix '!' should have optional type; type is 'Int?' func r17020197(_ x : Int?, y : Int) { - if x! { } // expected-error {{'Int' is not convertible to 'Bool'}} + if x! { } // expected-error {{cannot convert value of type 'Int' to expected condition type 'Bool'}} // QoI: diagnostic for using an integer in a condition is utterly terrible - if y {} // expected-error {{'Int' is not convertible to 'Bool'}} + if y {} // expected-error {{cannot convert value of type 'Int' to expected condition type 'Bool'}} } // QoI: Boolean expr not treated as Bool type when function return type is different diff --git a/test/Constraints/invalid_logicvalue_coercion.swift b/test/Constraints/invalid_logicvalue_coercion.swift index 32fb212948540..f703295130a12 100644 --- a/test/Constraints/invalid_logicvalue_coercion.swift +++ b/test/Constraints/invalid_logicvalue_coercion.swift @@ -2,8 +2,8 @@ class C {} var c = C() -if c as C { // expected-error{{'C' is not convertible to 'Bool'}} +if c as C { // expected-error{{cannot convert value of type 'C' to expected condition type 'Bool'}} } -if ({1} as () -> Int) { // expected-error{{'() -> Int' is not convertible to 'Bool'}} +if ({1} as () -> Int) { // expected-error{{cannot convert value of type '() -> Int' to expected condition type 'Bool'}} } diff --git a/test/Misc/misc_diagnostics.swift b/test/Misc/misc_diagnostics.swift index 685016582886b..f0cd75768adf2 100644 --- a/test/Misc/misc_diagnostics.swift +++ b/test/Misc/misc_diagnostics.swift @@ -22,8 +22,8 @@ let total = 15.0 let count = 7 let median = total / count // expected-error {{binary operator '/' cannot be applied to operands of type 'Double' and 'Int'}} expected-note {{overloads for '/' exist with these partially matching parameter lists:}} -if (1) {} // expected-error{{'Int' is not convertible to 'Bool'}} -if 1 {} // expected-error {{'Int' is not convertible to 'Bool'}} +if (1) {} // expected-error{{cannot convert value of type 'Int' to expected condition type 'Bool'}} +if 1 {} // expected-error {{cannot convert value of type 'Int' to expected condition type 'Bool'}} var a: [String] = [1] // expected-error{{cannot convert value of type 'Int' to expected element type 'String'}} var b: Int = [1, 2, 3] // expected-error{{cannot convert value of type '[Int]' to specified type 'Int'}} diff --git a/test/Parse/switch.swift b/test/Parse/switch.swift index 7d501284150c4..92c4184172122 100644 --- a/test/Parse/switch.swift +++ b/test/Parse/switch.swift @@ -62,9 +62,9 @@ case 10, case _ where x % 2 == 0, 20: x = 1 -case var y where y % 2 == 0: // expected-warning {{variable 'y' was never mutated; consider changing to 'let' constant}} +case var y where y % 2 == 0: x = y + 1 -case _ where 0: // expected-error {{'Int' is not convertible to 'Bool'}} +case _ where 0: // expected-error {{cannot convert value of type 'Int' to expected condition type 'Bool'}} x = 0 default: x = 1 diff --git a/test/Sema/pound_assert.swift b/test/Sema/pound_assert.swift index 598e2f05ea7f8..9f826e251ed1a 100644 --- a/test/Sema/pound_assert.swift +++ b/test/Sema/pound_assert.swift @@ -8,6 +8,6 @@ #assert(false, "error message") -#assert(123) // expected-error{{'Int' is not convertible to 'Bool'}} +#assert(123) // expected-error{{cannot convert value of type 'Int' to expected condition type 'Bool'}} -#assert(123, "error message") // expected-error{{'Int' is not convertible to 'Bool'}} +#assert(123, "error message") // expected-error{{cannot convert value of type 'Int' to expected condition type 'Bool'}} diff --git a/test/expr/expressions.swift b/test/expr/expressions.swift index c9de5cca8875c..6a8a4fc3525c1 100644 --- a/test/expr/expressions.swift +++ b/test/expr/expressions.swift @@ -799,14 +799,14 @@ func testOptionalTypeParsing(_ a : AnyObject) -> String { func testParenExprInTheWay() { let x = 42 - if x & 4.0 {} // expected-error {{binary operator '&' cannot be applied to operands of type 'Int' and 'Double'}} expected-note {{expected an argument list of type '(Int, Int)'}} - + if x & 4.0 {} // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} + // expected-error@-1 {{cannot convert value of type 'Int' to expected condition type 'Bool'}} if (x & 4.0) {} // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} - + // expected-error@-1 {{cannot convert value of type 'Int' to expected condition type 'Bool'}} if !(x & 4.0) {} // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} // expected-error@-1 {{cannot convert value of type 'Int' to expected argument type 'Bool'}} - - if x & x {} // expected-error {{'Int' is not convertible to 'Bool'}} + + if x & x {} // expected-error {{cannot convert value of type 'Int' to expected condition type 'Bool'}} } // Mixed method/property overload groups can cause a crash during constraint optimization diff --git a/test/stmt/if_while_var.swift b/test/stmt/if_while_var.swift index 750c1903d23ff..bffe794086c42 100644 --- a/test/stmt/if_while_var.swift +++ b/test/stmt/if_while_var.swift @@ -88,7 +88,7 @@ if 1 != 2, case let x? : Int? = 42 {} // expected-warning {{immutable value 'x' // Test error recovery. // Improve error recovery for malformed if statements -if 1 != 2, { // expected-error {{'() -> ()' is not convertible to 'Bool'}} +if 1 != 2, { // expected-error {{cannot convert value of type '() -> ()' to expected condition type 'Bool'}} } // expected-error {{expected '{' after 'if' condition}} if 1 != 2, 4 == 57 {} if 1 != 2, 4 == 57, let x = opt {} // expected-warning {{immutable value 'x' was never used; consider replacing with '_' or removing it}} diff --git a/test/stmt/statements.swift b/test/stmt/statements.swift index fbb9237d2f2a0..a22f4537450eb 100644 --- a/test/stmt/statements.swift +++ b/test/stmt/statements.swift @@ -59,7 +59,7 @@ func funcdecl5(_ a: Int, y: Int) { } // This diagnostic is terrible - rdar://12939553 - if x {} // expected-error {{'Int' is not convertible to 'Bool'}} + if x {} // expected-error {{cannot convert value of type 'Int' to expected condition type 'Bool'}} if true { if (B) { @@ -99,7 +99,7 @@ struct infloopbool { } func infloopbooltest() { - if (infloopbool()) {} // expected-error {{'infloopbool' is not convertible to 'Bool'}} + if (infloopbool()) {} // expected-error {{cannot convert value of type 'infloopbool' to expected condition type 'Bool'}} } // test "builder" API style @@ -566,9 +566,10 @@ func fn(x: Int) { } func bad_if() { - if 1 {} // expected-error {{'Int' is not convertible to 'Bool'}} - if (x: false) {} // expected-error {{'(x: Bool)' is not convertible to 'Bool'}} - if (x: 1) {} // expected-error {{'(x: Int)' is not convertible to 'Bool'}} + if 1 {} // expected-error {{cannot convert value of type 'Int' to expected condition type 'Bool'}} + if (x: false) {} // expected-error {{cannot convert value of type '(x: Bool)' to expected condition type 'Bool'}} + if (x: 1) {} // expected-error {{cannot convert value of type '(x: Int)' to expected condition type 'Bool'}} + if nil {} // expected-error {{'nil' is not compatible with expected condition type 'Bool'}} } // Typo correction for loop labels From f1cb0d11eff1adc42b2d0e6cfad9d2e39e74d7b3 Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Fri, 20 Sep 2019 12:43:51 -0700 Subject: [PATCH 109/199] Reflection: Make RemoteRef template not depend on Runtime. The only thing the Runtime affects is the width of the StoredPointer for the remote address, for which storing a uint64_t ought to be enough for anyone we care about so far. This will make it easier to store and use RemoteRefs in code that isn't or shouldn't ideally be templatized on Runtime (such as TypeRefBuilder, and ultimately ReflectionContext, from the Reflection library.) --- include/swift/Reflection/TypeRefBuilder.h | 4 +- include/swift/Remote/MetadataReader.h | 80 +++++++++++++---------- 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/include/swift/Reflection/TypeRefBuilder.h b/include/swift/Reflection/TypeRefBuilder.h index 7b8d3d828127c..7eb5838e802cd 100644 --- a/include/swift/Reflection/TypeRefBuilder.h +++ b/include/swift/Reflection/TypeRefBuilder.h @@ -531,8 +531,8 @@ class TypeRefBuilder { // underlying type if available. if (context->getKind() == ContextDescriptorKind::OpaqueType) { return Dem.createNode( - Node::Kind::OpaqueTypeDescriptorSymbolicReference, - (uintptr_t)context.getAddress()); + Node::Kind::OpaqueTypeDescriptorSymbolicReference, + (uintptr_t)context.template getAddress()); } return reader.buildContextMangling(context, Dem); diff --git a/include/swift/Remote/MetadataReader.h b/include/swift/Remote/MetadataReader.h index 95a9bf0d1d9da..8bbdb8b69059f 100644 --- a/include/swift/Remote/MetadataReader.h +++ b/include/swift/Remote/MetadataReader.h @@ -43,13 +43,10 @@ using TypeDecoder = swift::Demangle::TypeDecoder; /// A pointer to the local buffer of an object that also remembers the /// address at which it was stored remotely. -template +template class RemoteRef { -public: - using StoredPointer = typename Runtime::StoredPointer; - private: - StoredPointer Address; + uint64_t Address; const T *LocalBuffer; public: @@ -57,12 +54,18 @@ class RemoteRef { RemoteRef(std::nullptr_t _) : Address(0), LocalBuffer(nullptr) {} + template explicit RemoteRef(StoredPointer address, const T *localBuffer) - : Address(address), LocalBuffer(localBuffer) {} + : Address((uint64_t)address), LocalBuffer(localBuffer) {} - StoredPointer getAddress() const { + uint64_t getAddressData() const { return Address; } + + template + typename Runtime::StoredPointer getAddress() const { + return (typename Runtime::StoredPointer)getAddressData(); + } const T *getLocalBuffer() const { return LocalBuffer; @@ -76,6 +79,14 @@ class RemoteRef { assert(LocalBuffer); return LocalBuffer; } + + bool operator==(RemoteRef other) const { + return Address == other.Address; + } + + bool operator!=(RemoteRef other) const { + return !operator==(other); + } }; /// A structure, designed for use with std::unique_ptr, which destroys @@ -127,8 +138,7 @@ class MetadataReader { /// A cache of built types, keyed by the address of the type. std::unordered_map TypeCache; - using MetadataRef = - RemoteRef>; + using MetadataRef = RemoteRef>; using OwnedMetadataRef = std::unique_ptr, delete_with_free>; @@ -136,8 +146,7 @@ class MetadataReader { std::unordered_map MetadataCache; - using ContextDescriptorRef = - RemoteRef>; + using ContextDescriptorRef = RemoteRef>; using OwnedContextDescriptorRef = std::unique_ptr, delete_with_free>; @@ -1166,7 +1175,7 @@ class MetadataReader { return None; auto addressOfGenericArgAddress = - (Meta.getAddress() + + (Meta.template getAddress() + *offsetToGenericArgs * sizeof(StoredPointer) + index * sizeof(StoredPointer)); @@ -1292,29 +1301,31 @@ class MetadataReader { template StoredPointer resolveRelativeField( - RemoteRef base, const Field &field) { + RemoteRef base, const Field &field) { // Map the offset from within our local buffer to the remote address. auto distance = (intptr_t)&field - (intptr_t)base.getLocalBuffer(); - return resolveRelativeOffset(base.getAddress() + distance); + return resolveRelativeOffset( + base.template getAddress() + distance); } template Optional resolveNullableRelativeField( - RemoteRef base, const Field &field) { + RemoteRef base, const Field &field) { // Map the offset from within our local buffer to the remote address. auto distance = (intptr_t)&field - (intptr_t)base.getLocalBuffer(); - return resolveNullableRelativeOffset(base.getAddress() + distance); + return resolveNullableRelativeOffset( + base.template getAddress() + distance); } template Optional resolveNullableRelativeIndirectableField( - RemoteRef base, const Field &field) { + RemoteRef base, const Field &field) { // Map the offset from within our local buffer to the remote address. auto distance = (intptr_t)&field - (intptr_t)base.getLocalBuffer(); return resolveNullableRelativeIndirectableOffset( - base.getAddress() + distance); + base.template getAddress() + distance); } /// Given a pointer to an Objective-C class, try to read its class name. @@ -1838,7 +1849,8 @@ class MetadataReader { const RelativeTargetProtocolDescriptorPointer &protocol) { // Map the offset from within our local buffer to the remote address. auto distance = (intptr_t)&protocol - (intptr_t)descriptor.getLocalBuffer(); - StoredPointer targetAddress(descriptor.getAddress() + distance); + StoredPointer targetAddress( + descriptor.template getAddress() + distance); // Read the relative offset. int32_t relative; @@ -2071,7 +2083,8 @@ class MetadataReader { // address. auto distance = (intptr_t)&req.Layout - (intptr_t)descriptor.getLocalBuffer(); - StoredPointer targetAddress(descriptor.getAddress() + distance); + StoredPointer targetAddress( + descriptor.template getAddress() + distance); GenericRequirementLayoutKind kind; if (!Reader->readBytes(RemoteAddress(targetAddress), @@ -2106,7 +2119,7 @@ class MetadataReader { // Use the remote address to identify the anonymous context. char addressBuf[18]; snprintf(addressBuf, sizeof(addressBuf), "$%" PRIx64, - (uint64_t)descriptor.getAddress()); + (uint64_t)descriptor.getAddressData()); auto anonNode = dem.createNode(Node::Kind::AnonymousContext); CharVector addressStr; addressStr.append(addressBuf, dem); @@ -2269,7 +2282,7 @@ class MetadataReader { if (!offsetToGenericArgs) return {}; - auto genericArgsAddr = metadata.getAddress() + auto genericArgsAddr = metadata.template getAddress() + sizeof(StoredPointer) * *offsetToGenericArgs; std::vector builtSubsts; @@ -2326,9 +2339,8 @@ class MetadataReader { // If we've skipped an artificial subclasses, check the cache at // the superclass. (This also protects against recursion.) - if (skipArtificialSubclasses && - metadata.getAddress() != origMetadata.getAddress()) { - auto it = TypeCache.find(metadata.getAddress()); + if (skipArtificialSubclasses && metadata != origMetadata) { + auto it = TypeCache.find(metadata.template getAddress()); if (it != TypeCache.end()) return it->second; } @@ -2358,13 +2370,12 @@ class MetadataReader { if (!nominal) return BuiltType(); - TypeCache[metadata.getAddress()] = nominal; + TypeCache[metadata.template getAddress()] = nominal; // If we've skipped an artificial subclass, remove the // recursion-protection entry we made for it. - if (skipArtificialSubclasses && - metadata.getAddress() != origMetadata.getAddress()) { - TypeCache.erase(origMetadata.getAddress()); + if (skipArtificialSubclasses && metadata != origMetadata) { + TypeCache.erase(origMetadata.template getAddress()); } return nominal; @@ -2377,7 +2388,8 @@ class MetadataReader { return readNominalTypeFromMetadata(origMetadata, skipArtificialSubclasses); std::string className; - if (!readObjCClassName(origMetadata.getAddress(), className)) + auto origMetadataPtr = origMetadata.template getAddress(); + if (!readObjCClassName(origMetadataPtr, className)) return BuiltType(); BuiltType BuiltObjCClass = Builder.createObjCClassType(std::move(className)); @@ -2390,7 +2402,7 @@ class MetadataReader { skipArtificialSubclasses); } - TypeCache[origMetadata.getAddress()] = BuiltObjCClass; + TypeCache[origMetadataPtr] = BuiltObjCClass; return BuiltObjCClass; } @@ -2583,11 +2595,11 @@ class MetadataReader { } // end namespace swift namespace llvm { - template - struct simplify_type> { + template + struct simplify_type> { using SimpleType = const T *; static SimpleType - getSimplifiedValue(swift::remote::RemoteRef value) { + getSimplifiedValue(swift::remote::RemoteRef value) { return value.getLocalBuffer(); } }; From f8afae94448ec541fc6e682aad52b93c79afda2a Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 20 Sep 2019 12:46:44 -0700 Subject: [PATCH 110/199] [TypeChecker] Don't use contextual type for implicit `~=` type-check Type-check of implicit `~=` has to be handled specially because constraint system doesn't yet have a full access to pattern-matching context where `~=` is used which would produce incorrect diagnostics. --- lib/Sema/TypeCheckConstraints.cpp | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 26afc14d8854d..d5caba7c030cc 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -3147,9 +3147,32 @@ bool TypeChecker::typeCheckExprPattern(ExprPattern *EP, DeclContext *DC, Expr *matchCall = new (Context) BinaryExpr(matchOp, matchArgs, /*Implicit=*/true); - + // Check the expression as a condition. - bool hadError = typeCheckCondition(matchCall, DC); + // + // TODO: Type-check of `~=` operator can't (yet) use `typeCheckCondition` + // because that utilizes contextual type which interferes with diagnostics. + // We don't yet have a full access to pattern-matching context in + // constraint system, which is required to enable these situations + // to be properly diagnosed. + struct ConditionListener : public ExprTypeCheckListener { + // Add the appropriate Boolean constraint. + bool builtConstraints(ConstraintSystem &cs, Expr *expr) override { + // Otherwise, the result must be convertible to Bool. + auto boolDecl = cs.getASTContext().getBoolDecl(); + if (!boolDecl) + return true; + + // Condition must convert to Bool. + cs.addConstraint(ConstraintKind::Conversion, cs.getType(expr), + boolDecl->getDeclaredType(), + cs.getConstraintLocator(expr)); + return false; + } + }; + + ConditionListener listener; + bool hadError = !typeCheckExpression(matchCall, DC, &listener); // Save the type-checked expression in the pattern. EP->setMatchExpr(matchCall); // Set the type on the pattern. From 232185ec72dccce2fa0633bf324020c42b3a80bc Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 20 Sep 2019 13:32:14 -0700 Subject: [PATCH 111/199] [Diagnostics] Don't try to diagnose immutability failures in boolean context --- lib/Sema/CSDiagnostics.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 826a526f7168a..afc8151a4bfdf 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -1294,6 +1294,13 @@ bool RValueTreatedAsLValueFailure::diagnoseAsError() { Expr *diagExpr = getRawAnchor(); SourceLoc loc = diagExpr->getLoc(); + auto &cs = getConstraintSystem(); + // Assignment is not allowed inside of a condition, + // so let's not diagnose immutability, because + // most likely the problem is related to use of `=` itself. + if (cs.getContextualTypePurpose() == CTP_Condition) + return false; + if (auto assignExpr = dyn_cast(diagExpr)) { diagExpr = assignExpr->getDest(); } From 1584e87aa7dc92f1c4515da39367a63de1991e3a Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Fri, 20 Sep 2019 14:02:53 -0700 Subject: [PATCH 112/199] Revert "[SyntaxParse] Parse generic parameter clause and generic where clause" --- cmake/modules/SwiftHandleGybSources.cmake | 2 - include/swift/Parse/ASTGen.h | 24 +- include/swift/Parse/Lexer.h | 4 +- .../swift/Parse/ParsedSyntaxBuilders.h.gyb | 2 +- include/swift/Parse/ParsedSyntaxNodes.h.gyb | 6 +- .../swift/Parse/ParsedSyntaxRecorder.h.gyb | 2 +- include/swift/Parse/Parser.h | 24 +- include/swift/Syntax/SyntaxBuilders.h.gyb | 2 +- include/swift/Syntax/SyntaxFactory.h.gyb | 2 +- include/swift/Syntax/SyntaxKind.h.gyb | 14 +- include/swift/Syntax/SyntaxNodes.h.gyb | 6 +- include/swift/Syntax/SyntaxVisitor.h.gyb | 2 +- lib/Parse/ASTGen.cpp | 195 +------- lib/Parse/ParseDecl.cpp | 1 - lib/Parse/ParseGeneric.cpp | 458 +++++++++--------- lib/Parse/ParseType.cpp | 114 +++-- lib/Parse/ParsedSyntaxBuilders.cpp.gyb | 2 +- lib/Parse/ParsedSyntaxNodes.cpp.gyb | 2 +- lib/Parse/ParsedSyntaxRecorder.cpp.gyb | 4 +- lib/Parse/Parser.cpp | 2 +- lib/ParseSIL/ParseSIL.cpp | 6 +- lib/Syntax/SyntaxBuilders.cpp.gyb | 2 +- lib/Syntax/SyntaxFactory.cpp.gyb | 10 +- lib/Syntax/SyntaxKind.cpp.gyb | 8 +- lib/Syntax/SyntaxNodes.cpp.gyb | 2 +- lib/Syntax/SyntaxVisitor.cpp.gyb | 4 +- test/Parse/invalid.swift | 2 +- .../round_trip_parse_gen.swift.withkinds | 22 +- unittests/Syntax/DeclSyntaxTests.cpp | 6 +- utils/gyb_syntax_support/GenericNodes.py | 55 +-- .../NodeSerializationCodes.py | 3 - utils/gyb_syntax_support/SILOnlyNodes.py | 9 - utils/gyb_syntax_support/__init__.py | 1 - 33 files changed, 364 insertions(+), 634 deletions(-) delete mode 100644 utils/gyb_syntax_support/SILOnlyNodes.py diff --git a/cmake/modules/SwiftHandleGybSources.cmake b/cmake/modules/SwiftHandleGybSources.cmake index 7e858badf8e81..1d37e4ae80958 100644 --- a/cmake/modules/SwiftHandleGybSources.cmake +++ b/cmake/modules/SwiftHandleGybSources.cmake @@ -121,9 +121,7 @@ function(handle_gyb_sources dependency_out_var_name sources_var_name arch) "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/DeclNodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/ExprNodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/GenericNodes.py" - "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/NodeSerializationCodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/PatternNodes.py" - "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/SILOnlyNodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/StmtNodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/TypeNodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/Token.py" diff --git a/include/swift/Parse/ASTGen.h b/include/swift/Parse/ASTGen.h index 591c8034548ea..4f29a8bb3a8b0 100644 --- a/include/swift/Parse/ASTGen.h +++ b/include/swift/Parse/ASTGen.h @@ -22,24 +22,21 @@ namespace swift { /// Generates AST nodes from Syntax nodes. -class Parser; class ASTGen { ASTContext &Context; /// Type cache to prevent multiple transformations of the same syntax node. llvm::DenseMap TypeCache; - Parser &P; + PersistentParserState **ParserState; // FIXME: remove when Syntax can represent all types and ASTGen can handle them /// Types that cannot be represented by Syntax or generated by ASTGen. llvm::DenseMap Types; - llvm::DenseMap ParsedDeclAttrs; - public: - ASTGen(ASTContext &Context, Parser &P) - : Context(Context), P(P) {} + ASTGen(ASTContext &Context, PersistentParserState **ParserState) + : Context(Context), ParserState(ParserState) {} SourceLoc generate(syntax::TokenSyntax Tok, SourceLoc &Loc); @@ -73,15 +70,6 @@ class ASTGen { llvm::SmallVector generate(syntax::GenericArgumentListSyntax Args, SourceLoc &Loc); - GenericParamList * - generate(syntax::GenericParameterClauseListSyntax clause, SourceLoc &Loc); - GenericParamList * - generate(syntax::GenericParameterClauseSyntax clause, SourceLoc &Loc); - Optional - generate(syntax::GenericRequirementSyntax req, SourceLoc &Loc); - LayoutConstraint - generate(syntax::LayoutConstraintSyntax req, SourceLoc &Loc); - /// Copy a numeric literal value into AST-owned memory, stripping underscores /// so the semantic part of the value can be parsed by APInt/APFloat parsers. static StringRef copyAndStripUnderscores(StringRef Orig, ASTContext &Context); @@ -114,8 +102,6 @@ class ASTGen { ValueDecl *lookupInScope(DeclName Name); - void addToScope(ValueDecl *D, bool diagnoseRedefinitions = true); - TypeRepr *cacheType(syntax::TypeSyntax Type, TypeRepr *TypeAST); TypeRepr *lookupType(syntax::TypeSyntax Type); @@ -126,10 +112,6 @@ class ASTGen { bool hasType(const SourceLoc &Loc) const; TypeRepr *getType(const SourceLoc &Loc) const; - - void addDeclAttributes(DeclAttributes attrs, SourceLoc Loc); - bool hasDeclAttributes(SourceLoc Loc) const; - DeclAttributes getDeclAttributes(SourceLoc Loc) const; }; } // namespace swift diff --git a/include/swift/Parse/Lexer.h b/include/swift/Parse/Lexer.h index 2849c41f1eca3..8441a12dc17d4 100644 --- a/include/swift/Parse/Lexer.h +++ b/include/swift/Parse/Lexer.h @@ -200,8 +200,8 @@ class Lexer { ParsedTrivia &TrailingTriviaResult) { Result = NextToken; if (TriviaRetention == TriviaRetentionMode::WithTrivia) { - std::swap(LeadingTriviaResult, LeadingTrivia); - std::swap(TrailingTriviaResult, TrailingTrivia); + LeadingTriviaResult = {LeadingTrivia}; + TrailingTriviaResult = {TrailingTrivia}; } if (Result.isNot(tok::eof)) lexImpl(); diff --git a/include/swift/Parse/ParsedSyntaxBuilders.h.gyb b/include/swift/Parse/ParsedSyntaxBuilders.h.gyb index 0cfcf69bd32ce..90aba5e9eb212 100644 --- a/include/swift/Parse/ParsedSyntaxBuilders.h.gyb +++ b/include/swift/Parse/ParsedSyntaxBuilders.h.gyb @@ -30,7 +30,7 @@ namespace swift { class ParsedRawSyntaxRecorder; class SyntaxParsingContext; -% for node in SYNTAX_NODES + SILONLY_NODES: +% for node in SYNTAX_NODES: % if node.is_buildable(): % child_count = len(node.children) class Parsed${node.name}Builder { diff --git a/include/swift/Parse/ParsedSyntaxNodes.h.gyb b/include/swift/Parse/ParsedSyntaxNodes.h.gyb index 8883b2ed796e8..5bbc07321f49d 100644 --- a/include/swift/Parse/ParsedSyntaxNodes.h.gyb +++ b/include/swift/Parse/ParsedSyntaxNodes.h.gyb @@ -28,20 +28,20 @@ namespace swift { % # Emit the non-collection classes first, then emit the collection classes % # that reference these classes. -% for node in SYNTAX_NODES + SILONLY_NODES: +% for node in SYNTAX_NODES: % if not node.is_syntax_collection(): class Parsed${node.name}; % end % end -% for node in SYNTAX_NODES + SILONLY_NODES: +% for node in SYNTAX_NODES: % if node.is_syntax_collection(): using Parsed${node.name} = ParsedSyntaxCollection; % end % end -% for node in SYNTAX_NODES + SILONLY_NODES: +% for node in SYNTAX_NODES: % if not node.is_syntax_collection(): % qualifier = "" if node.is_base() else "final" % for line in dedented_lines(node.description): diff --git a/include/swift/Parse/ParsedSyntaxRecorder.h.gyb b/include/swift/Parse/ParsedSyntaxRecorder.h.gyb index 5600ade0b5028..51b56c73aea07 100644 --- a/include/swift/Parse/ParsedSyntaxRecorder.h.gyb +++ b/include/swift/Parse/ParsedSyntaxRecorder.h.gyb @@ -31,7 +31,7 @@ class SyntaxParsingContext; struct ParsedSyntaxRecorder { -% for node in SYNTAX_NODES + SILONLY_NODES: +% for node in SYNTAX_NODES: % if node.children: % child_params = [] % for child in node.children: diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 91ee72590704c..9ccac31e34256 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -695,19 +695,11 @@ class Parser { /// plain Tok.is(T1) check). bool skipUntilTokenOrEndOfLine(tok T1); - //-------------------------------------------------------------------------// - // Ignore token APIs. - // This is used when we skip gabage text in the source text. - - /// Ignore the current single token. void ignoreToken(); void ignoreToken(tok Kind) { - /// Ignore the current single token asserting its kind. assert(Tok.is(Kind)); ignoreToken(); } - /// Conditionally ignore the current single token if it matches with the \p - /// Kind. bool ignoreIf(tok Kind) { if (!Tok.is(Kind)) return false; @@ -1181,8 +1173,7 @@ class Parser { using TypeASTResult = ParserResult; using TypeResult = ParsedSyntaxResult; - ParsedSyntaxResult - parseLayoutConstraintSyntax(); + LayoutConstraint parseLayoutConstraint(Identifier LayoutConstraintID); TypeResult parseTypeSyntax(); TypeResult parseTypeSyntax(Diag<> MessageID, bool HandleCodeCompletion = true, @@ -1606,19 +1597,8 @@ class Parser { //===--------------------------------------------------------------------===// // Generics Parsing - ParserResult parseSILGenericParams(); - - ParserStatus parseSILGenericParamsSyntax( - Optional &result); - - ParsedSyntaxResult - parseGenericParameterClauseSyntax(); - - ParsedSyntaxResult - parseGenericWhereClauseSyntax(bool &FirstTypeInComplete, - bool AllowLayoutConstraints = false); - ParserResult parseGenericParameters(); + ParserResult parseGenericParameters(SourceLoc LAngleLoc); ParserStatus parseGenericParametersBeforeWhere(SourceLoc LAngleLoc, SmallVectorImpl &GenericParams); ParserResult maybeParseGenericParams(); diff --git a/include/swift/Syntax/SyntaxBuilders.h.gyb b/include/swift/Syntax/SyntaxBuilders.h.gyb index 177d6779fe45e..7fe71ed159a3d 100644 --- a/include/swift/Syntax/SyntaxBuilders.h.gyb +++ b/include/swift/Syntax/SyntaxBuilders.h.gyb @@ -29,7 +29,7 @@ namespace syntax { class SyntaxArena; -% for node in SYNTAX_NODES + SILONLY_NODES: +% for node in SYNTAX_NODES: % if node.is_buildable(): % child_count = len(node.children) class ${node.name}Builder { diff --git a/include/swift/Syntax/SyntaxFactory.h.gyb b/include/swift/Syntax/SyntaxFactory.h.gyb index be88f173d5697..387279d73f891 100644 --- a/include/swift/Syntax/SyntaxFactory.h.gyb +++ b/include/swift/Syntax/SyntaxFactory.h.gyb @@ -71,7 +71,7 @@ struct SyntaxFactory { static Syntax makeBlankCollectionSyntax(SyntaxKind Kind); -% for node in SYNTAX_NODES + SILONLY_NODES: +% for node in SYNTAX_NODES: % if node.children: % child_params = [] % for child in node.children: diff --git a/include/swift/Syntax/SyntaxKind.h.gyb b/include/swift/Syntax/SyntaxKind.h.gyb index 10291bad736b7..21f344a572352 100644 --- a/include/swift/Syntax/SyntaxKind.h.gyb +++ b/include/swift/Syntax/SyntaxKind.h.gyb @@ -2,7 +2,7 @@ from gyb_syntax_support import * from gyb_syntax_support.kinds import SYNTAX_BASE_KINDS grouped_nodes = { kind: [] for kind in SYNTAX_BASE_KINDS } - for node in SYNTAX_NODES + SILONLY_NODES: + for node in SYNTAX_NODES: grouped_nodes[node.base_kind].append(node) # -*- mode: C++ -*- # Ignore the following admonition; it applies to the resulting .h file only @@ -89,14 +89,12 @@ struct WrapperTypeTraits { return 0; case syntax::SyntaxKind::Unknown: return 1; -% for node in SYNTAX_NODES: +% for name, nodes in grouped_nodes.items(): +% for node in nodes: case syntax::SyntaxKind::${node.syntax_kind}: return ${SYNTAX_NODE_SERIALIZATION_CODES[node.syntax_kind]}; +% end % end -% for node in SILONLY_NODES: - case syntax::SyntaxKind::${node.syntax_kind}: -% end - llvm_unreachable("unserializable syntax kind"); } llvm_unreachable("unhandled kind"); } @@ -124,10 +122,6 @@ struct ScalarReferenceTraits { case syntax::SyntaxKind::${node.syntax_kind}: return "\"${node.syntax_kind}\""; % end -% for node in SILONLY_NODES: - case syntax::SyntaxKind::${node.syntax_kind}: -% end - llvm_unreachable("unserializable syntax kind"); } llvm_unreachable("unhandled kind"); } diff --git a/include/swift/Syntax/SyntaxNodes.h.gyb b/include/swift/Syntax/SyntaxNodes.h.gyb index 0e4a9a9bf5d54..65219ce8489d1 100644 --- a/include/swift/Syntax/SyntaxNodes.h.gyb +++ b/include/swift/Syntax/SyntaxNodes.h.gyb @@ -32,13 +32,13 @@ namespace syntax { % # Emit the non-collection classes first, then emit the collection classes % # that reference these classes. -% for node in SYNTAX_NODES + SILONLY_NODES: +% for node in SYNTAX_NODES: % if not node.is_syntax_collection(): class ${node.name}; % end % end -% for node in SYNTAX_NODES + SILONLY_NODES: +% for node in SYNTAX_NODES: % if node.is_syntax_collection(): using ${node.name} = SyntaxCollection()) TypeAST = generate(*SimpleIdentifier, Loc); @@ -223,7 +224,7 @@ TypeRepr *ASTGen::generate(AttributedTypeSyntax Type, SourceLoc &Loc) { if (AttrKind == TAK_convention) { auto Argument = Attr.getArgument()->castTo(); - auto Convention = Context.getIdentifier(Argument.getIdentifierText()); + auto Convention = Context.getIdentifier(Argument.getText()); TypeAttrs.convention = Convention.str(); } @@ -338,10 +339,9 @@ TypeRepr *ASTGen::generateSimpleOrMemberIdentifier(T Type, SourceLoc &Loc) { auto FirstComponent = IdentType->getComponentRange().front(); // Lookup element #0 through our current scope chains in case it is some // thing local (this returns null if nothing is found). - if (auto Entry = lookupInScope(FirstComponent->getIdentifier())) { + if (auto Entry = lookupInScope(FirstComponent->getIdentifier())) if (auto *TD = dyn_cast(Entry)) FirstComponent->setValue(TD, nullptr); - } return IdentType; } @@ -369,11 +369,6 @@ TypeRepr *ASTGen::generate(SimpleTypeIdentifierSyntax Type, SourceLoc &Loc) { auto AnyLoc = advanceLocBegin(Loc, Type.getName()); return CompositionTypeRepr::createEmptyComposition(Context, AnyLoc); } - if (Type.getName().getText() == "class") { - auto classLoc = advanceLocBegin(Loc, Type.getName()); - return new (Context) SimpleIdentTypeRepr(classLoc, - Context.getIdentifier("AnyObject")); - } return generateSimpleOrMemberIdentifier(Type, Loc); } @@ -517,162 +512,6 @@ StringRef ASTGen::copyAndStripUnderscores(StringRef Orig, ASTContext &Context) { return StringRef(start, p - start); } -GenericParamList *ASTGen::generate(GenericParameterClauseListSyntax clauses, - SourceLoc &Loc) { - GenericParamList *curr = nullptr; - - // The first one is the outmost generic parameter list. - for (const auto &clause : clauses) { - auto params = generate(clause, Loc); - if (!params) - continue; - params->setOuterParameters(curr); - curr = params; - } - - return curr; -} - -GenericParamList *ASTGen::generate(GenericParameterClauseSyntax clause, - SourceLoc &Loc) { - SmallVector params; - params.reserve(clause.getGenericParameterList().getNumChildren()); - - for (auto elem : clause.getGenericParameterList()) { - - DeclAttributes attrs; - if (auto attrsSyntax = elem.getAttributes()) { - auto attrsLoc = advanceLocBegin(Loc, *attrsSyntax->getFirstToken()); - attrs = getDeclAttributes(attrsLoc); - } - Identifier name = Context.getIdentifier(elem.getName().getIdentifierText()); - SourceLoc nameLoc = advanceLocBegin(Loc, elem.getName()); - - // We always create generic type parameters with an invalid depth. - // Semantic analysis fills in the depth when it processes the generic - // parameter list. - auto param = new (Context) - GenericTypeParamDecl(P.CurDeclContext, name, nameLoc, - GenericTypeParamDecl::InvalidDepth, params.size()); - - if (auto inherited = elem.getInheritedType()) { - if (auto ty = generate(*inherited, Loc)) { - SmallVector constraints = {generate(*inherited, Loc)}; - param->setInherited(Context.AllocateCopy(constraints)); - } - } - - // Attach attributes. - param->getAttrs() = attrs; - - // Add this parameter to the scope. - addToScope(param); - - params.push_back(param); - } - if (params.empty()) - return nullptr; - - SourceLoc whereLoc; - SmallVector requirements; - if (auto whereClause = clause.getObsoletedWhereClause()) { - requirements.reserve(whereClause->getRequirementList().size()); - for (auto elem : whereClause->getRequirementList()) { - if (auto req = generate(elem, Loc)) - requirements.push_back(*req); - } - // There's an invariant that valid 'where' loc means that there's at - // at least one valid requirement. - if (!requirements.empty()) - whereLoc = advanceLocBegin(Loc, whereClause->getWhereKeyword()); - } - - auto lAngleLoc = advanceLocBegin(Loc, clause.getLeftAngleBracket()); - auto rAngleLoc = advanceLocBegin(Loc, clause.getRightAngleBracket()); - return GenericParamList::create(Context, lAngleLoc, params, whereLoc, - requirements, rAngleLoc); -} - -Optional ASTGen::generate(syntax::GenericRequirementSyntax req, - SourceLoc &Loc) { - if (auto sameTypeReq = req.getBody().getAs()) { - auto firstType = generate(sameTypeReq->getLeftTypeIdentifier(), Loc); - auto secondType = generate(sameTypeReq->getRightTypeIdentifier(), Loc); - if (!firstType || !secondType) - return None; - return RequirementRepr::getSameType( - firstType, advanceLocBegin(Loc, sameTypeReq->getEqualityToken()), - secondType); - } else if (auto conformanceReq = - req.getBody().getAs()) { - auto firstType = generate(conformanceReq->getLeftTypeIdentifier(), Loc); - auto secondType = generate(conformanceReq->getRightTypeIdentifier(), Loc); - if (!firstType || !secondType) - return None; - return RequirementRepr::getTypeConstraint( - firstType, advanceLocBegin(Loc, conformanceReq->getColon()), - secondType); - } else if (auto layoutReq = req.getBody().getAs()) { - auto firstType = generate(layoutReq->getLeftTypeIdentifier(), Loc); - auto layout = generate(layoutReq->getLayoutConstraint(), Loc); - if (!firstType || layout.isNull()) - return None; - auto colonLoc = advanceLocBegin(Loc, layoutReq->getColon()); - auto layoutLoc = advanceLocBegin(Loc, layoutReq->getLayoutConstraint()); - return RequirementRepr::getLayoutConstraint( - firstType, colonLoc, LayoutConstraintLoc(layout, layoutLoc)); - } else { - llvm_unreachable("invalid syntax kind for requirement body"); - } -} - -static LayoutConstraintKind getLayoutConstraintKind(Identifier &id, - ASTContext &Ctx) { - if (id == Ctx.Id_TrivialLayout) - return LayoutConstraintKind::TrivialOfExactSize; - if (id == Ctx.Id_TrivialAtMostLayout) - return LayoutConstraintKind::TrivialOfAtMostSize; - if (id == Ctx.Id_RefCountedObjectLayout) - return LayoutConstraintKind::RefCountedObject; - if (id == Ctx.Id_NativeRefCountedObjectLayout) - return LayoutConstraintKind::NativeRefCountedObject; - if (id == Ctx.Id_ClassLayout) - return LayoutConstraintKind::Class; - if (id == Ctx.Id_NativeClassLayout) - return LayoutConstraintKind::NativeClass; - return LayoutConstraintKind::UnknownLayout; -} - -LayoutConstraint ASTGen::generate(LayoutConstraintSyntax constraint, - SourceLoc &Loc) { - auto name = Context.getIdentifier(constraint.getName().getIdentifierText()); - auto constraintKind = getLayoutConstraintKind(name, Context); - assert(constraintKind != LayoutConstraintKind::UnknownLayout); - - // Non-trivial constraint kinds don't have size/alignment. - // TODO: Diagnose if it's supplied? - if (!LayoutConstraintInfo::isTrivial(constraintKind)) - return LayoutConstraint::getLayoutConstraint(constraintKind, Context); - - // '_Trivial' without explicit size/alignment. - if (!constraint.getSize()) - return LayoutConstraint::getLayoutConstraint(LayoutConstraintKind::Trivial, - Context); - - int size = 0; - if (auto sizeSyntax = constraint.getSize()) - sizeSyntax->getText().getAsInteger(10, size); - assert(size >= 0); - - int alignment = 0; - if (auto alignmentSyntax = constraint.getAlignment()) - alignmentSyntax->getText().getAsInteger(10, alignment); - assert(alignment >= 0); - - return LayoutConstraint::getLayoutConstraint(constraintKind, size, alignment, - Context); -} - SourceLoc ASTGen::advanceLocBegin(const SourceLoc &Loc, const Syntax &Node) { return Loc.getAdvancedLoc(Node.getAbsolutePosition().getOffset()); } @@ -711,11 +550,9 @@ MagicIdentifierLiteralExpr::Kind ASTGen::getMagicIdentifierLiteralKind(tok Kind) } ValueDecl *ASTGen::lookupInScope(DeclName Name) { - return P.lookupInScope(Name); -} - -void ASTGen::addToScope(ValueDecl *D, bool diagnoseRedefinitions) { - P.addToScope(D, diagnoseRedefinitions); + return Context.LangOpts.EnableASTScopeLookup && Context.LangOpts.DisableParserLookup + ? nullptr + : (*ParserState)->getScopeInfo().lookupValueName(Name); } TypeRepr *ASTGen::cacheType(TypeSyntax Type, TypeRepr *TypeAST) { @@ -739,15 +576,3 @@ bool ASTGen::hasType(const SourceLoc &Loc) const { TypeRepr *ASTGen::getType(const SourceLoc &Loc) const { return Types.find(Loc)->second; } - -void ASTGen::addDeclAttributes(DeclAttributes attrs, SourceLoc Loc) { - ParsedDeclAttrs.insert({Loc, attrs}); -} - -bool ASTGen::hasDeclAttributes(SourceLoc Loc) const { - return ParsedDeclAttrs.find(Loc) != ParsedDeclAttrs.end(); -} - -DeclAttributes ASTGen::getDeclAttributes(SourceLoc Loc) const { - return ParsedDeclAttrs.find(Loc)->second; -} diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index aac270c73ddae..8400738a7a5b5 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -16,7 +16,6 @@ #include "swift/Parse/Parser.h" #include "swift/Parse/CodeCompletionCallbacks.h" -#include "swift/Parse/ParsedSyntaxBuilders.h" #include "swift/Parse/ParsedSyntaxRecorder.h" #include "swift/Parse/ParseSILSupport.h" #include "swift/Parse/SyntaxParsingContext.h" diff --git a/lib/Parse/ParseGeneric.cpp b/lib/Parse/ParseGeneric.cpp index ee00e32c6aad8..912784c0ad044 100644 --- a/lib/Parse/ParseGeneric.cpp +++ b/lib/Parse/ParseGeneric.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,185 +10,185 @@ // //===----------------------------------------------------------------------===// // -// Generic Parsing +// Generic Parsing and AST Building // //===----------------------------------------------------------------------===// #include "swift/Parse/Parser.h" #include "swift/AST/DiagnosticsParse.h" -#include "swift/Parse/ParsedSyntaxBuilders.h" -#include "swift/Parse/ParsedSyntaxRecorder.h" +#include "swift/Parse/CodeCompletionCallbacks.h" #include "swift/Parse/SyntaxParsingContext.h" - +#include "swift/Parse/Lexer.h" +#include "swift/Syntax/SyntaxBuilders.h" +#include "swift/Syntax/SyntaxNodes.h" using namespace swift; using namespace swift::syntax; -/// Parse a list of generic parameters. -/// -/// generic-parameter-clause-list: -/// generic-parameter-clause generic-parameter-clause* -ParserStatus Parser::parseSILGenericParamsSyntax( - Optional &result) { - assert(isInSILMode()); - ParserStatus status; - if (!startsWithLess(Tok)) - return status; - - SmallVector clauses; - do { - auto result = parseGenericParameterClauseSyntax(); - status |= result.getStatus(); - if (!result.isNull()) - clauses.push_back(result.get()); - } while (startsWithLess(Tok)); - - result = ParsedSyntaxRecorder::makeGenericParameterClauseList(clauses, - *SyntaxContext); - return status; -} - -/// Parse a sequence of generic parameters, e.g. '' -/// along with an optional requires clause. +/// parseGenericParameters - Parse a sequence of generic parameters, e.g., +/// < T : Comparable, U : Container> along with an optional requires clause. /// -/// generic-parameter-clause: -/// '<' generic-paramter (',' generic-parameter)* where-clause? '>' +/// generic-params: +/// '<' generic-param (',' generic-param)* where-clause? '>' /// -/// generic-parameter: +/// generic-param: /// identifier -/// identifier ':' type -ParsedSyntaxResult -Parser::parseGenericParameterClauseSyntax() { +/// identifier ':' type-identifier +/// identifier ':' type-composition +/// +/// When parsing the generic parameters, this routine establishes a new scope +/// and adds those parameters to the scope. +ParserResult Parser::parseGenericParameters() { + SyntaxParsingContext GPSContext(SyntaxContext, SyntaxKind::GenericParameterClause); + // Parse the opening '<'. assert(startsWithLess(Tok) && "Generic parameter list must start with '<'"); - ParsedGenericParameterClauseSyntaxBuilder builder(*SyntaxContext); - ParserStatus status; - - // Parse '<'. - SourceLoc LAngleLoc = Tok.getLoc(); - builder.useLeftAngleBracket(consumeStartingLessSyntax()); + return parseGenericParameters(consumeStartingLess()); +} - // Parse parameters. - bool hasNext = true; +ParserStatus +Parser::parseGenericParametersBeforeWhere(SourceLoc LAngleLoc, + SmallVectorImpl &GenericParams) { + ParserStatus Result; + SyntaxParsingContext GPSContext(SyntaxContext, SyntaxKind::GenericParameterList); + bool HasNextParam; do { - ParsedGenericParameterSyntaxBuilder paramBuilder(*SyntaxContext); + SyntaxParsingContext GParamContext(SyntaxContext, SyntaxKind::GenericParameter); + // Note that we're parsing a declaration. + StructureMarkerRAII ParsingDecl(*this, Tok.getLoc(), + StructureMarkerKind::Declaration); + + if (ParsingDecl.isFailed()) { + return makeParserError(); + } // Parse attributes. - // TODO: Implement syntax attribute parsing. - DeclAttributes attrsAST; - parseDeclAttributeList(attrsAST); - auto attrs = SyntaxContext->popIf(); - if (attrs) { - paramBuilder.useAttributes(std::move(*attrs)); - Generator.addDeclAttributes(attrsAST, attrsAST.getStartLoc()); - } + DeclAttributes attributes; + if (Tok.hasComment()) + attributes.add(new (Context) RawDocCommentAttr(Tok.getCommentRange())); + parseDeclAttributeList(attributes); // Parse the name of the parameter. - auto ident = Context.getIdentifier(Tok.getText()); - auto name = parseIdentifierSyntax(diag::expected_generics_parameter_name); - if (!name) { - status.setIsParseError(); + Identifier Name; + SourceLoc NameLoc; + if (parseIdentifier(Name, NameLoc, + diag::expected_generics_parameter_name)) { + Result.setIsParseError(); break; } - paramBuilder.useName(std::move(*name)); // Parse the ':' followed by a type. + SmallVector Inherited; if (Tok.is(tok::colon)) { - paramBuilder.useColon(consumeTokenSyntax(tok::colon)); + (void)consumeToken(); + ParserResult Ty; + if (Tok.isAny(tok::identifier, tok::code_complete, tok::kw_protocol, tok::kw_Any)) { - auto tyResult = parseTypeSyntax(); - status |= tyResult.getStatus(); - if (auto ty = tyResult.getOrNull()) - paramBuilder.useInheritedType(std::move(*ty)); + Ty = parseType(); + } else if (Tok.is(tok::kw_class)) { + diagnose(Tok, diag::unexpected_class_constraint); + diagnose(Tok, diag::suggest_anyobject) + .fixItReplace(Tok.getLoc(), "AnyObject"); + consumeToken(); + Result.setIsParseError(); } else { - if (Tok.is(tok::kw_class)) { - diagnose(Tok, diag::unexpected_class_constraint); - diagnose(Tok, diag::suggest_anyobject) - .fixItReplace(Tok.getLoc(), "AnyObject"); - Tok.setKind(tok::identifier); - auto ty = ParsedSyntaxRecorder::makeSimpleTypeIdentifier( - consumeTokenSyntax(), None, *SyntaxContext); - paramBuilder.useInheritedType(std::move(ty)); - } else { - diagnose(Tok, diag::expected_generics_type_restriction, ident); - - paramBuilder.useInheritedType( - ParsedSyntaxRecorder::makeUnknownType({}, *SyntaxContext)); - } - status.setIsParseError(); + diagnose(Tok, diag::expected_generics_type_restriction, Name); + Result.setIsParseError(); } + + if (Ty.hasCodeCompletion()) + return makeParserCodeCompletionStatus(); + + if (Ty.isNonNull()) + Inherited.push_back(Ty.get()); } - // Parse ',' - hasNext = Tok.is(tok::comma); - if (hasNext) - paramBuilder.useTrailingComma(consumeTokenSyntax(tok::comma)); + // We always create generic type parameters with an invalid depth. + // Semantic analysis fills in the depth when it processes the generic + // parameter list. + auto Param = new (Context) GenericTypeParamDecl(CurDeclContext, Name, NameLoc, + GenericTypeParamDecl::InvalidDepth, + GenericParams.size()); + if (!Inherited.empty()) + Param->setInherited(Context.AllocateCopy(Inherited)); + GenericParams.push_back(Param); - builder.addGenericParameterListMember(paramBuilder.build()); - } while (hasNext); + // Attach attributes. + Param->getAttrs() = attributes; - // Parse optional where clause. - SourceLoc whereLoc; - if (Tok.is(tok::kw_where)) { - SmallVector requirementAST; - bool FirstTypeInComplete = false; - auto where = parseGenericWhereClauseSyntax(FirstTypeInComplete); - builder.useObsoletedWhereClause(where.get()); - } + // Add this parameter to the scope. + addToScope(Param); + // Parse the comma, if the list continues. + HasNextParam = consumeIf(tok::comma); + } while (HasNextParam); + + return Result; +} + +ParserResult +Parser::parseGenericParameters(SourceLoc LAngleLoc) { + // Parse the generic parameter list. + SmallVector GenericParams; + auto Result = parseGenericParametersBeforeWhere(LAngleLoc, GenericParams); + + // Return early if there was code completion token. + if (Result.hasCodeCompletion()) + return Result; + auto Invalid = Result.isError(); + + // Parse the optional where-clause. + SourceLoc WhereLoc; + SmallVector Requirements; + bool FirstTypeInComplete; + if (Tok.is(tok::kw_where) && + parseGenericWhereClause(WhereLoc, Requirements, + FirstTypeInComplete).isError()) { + Invalid = true; + } + // Parse the closing '>'. + SourceLoc RAngleLoc; if (startsWithGreater(Tok)) { - builder.useRightAngleBracket(consumeStartingGreaterSyntax()); + RAngleLoc = consumeStartingGreater(); } else { - if (!status.isError()) { + if (!Invalid) { diagnose(Tok, diag::expected_rangle_generics_param); diagnose(LAngleLoc, diag::opening_angle); + Invalid = true; } // Skip until we hit the '>'. - if (ignoreUntilGreaterInTypeList()) - builder.useRightAngleBracket(consumeStartingGreaterSyntax()); - status.setIsParseError(); + RAngleLoc = skipUntilGreaterInTypeList(); } - return makeParsedResult(builder.build(), status); -} - -ParserResult Parser::parseGenericParameters() { - auto loc = leadingTriviaLoc(); - auto syntaxResult = parseGenericParameterClauseSyntax(); - if (syntaxResult.isNull()) - return syntaxResult.getStatus(); - SyntaxContext->addSyntax(syntaxResult.get()); - - auto clause = SyntaxContext->topNode(); - if (clause.getGenericParameterList().empty()) + if (GenericParams.empty()) return nullptr; - return makeParserResult(syntaxResult.getStatus(), - Generator.generate(clause, loc)); + + return makeParserResult(GenericParamList::create(Context, LAngleLoc, + GenericParams, WhereLoc, + Requirements, RAngleLoc)); } ParserResult Parser::maybeParseGenericParams() { if (!startsWithLess(Tok)) return nullptr; - return parseGenericParameters(); -} -ParserResult Parser::parseSILGenericParams() { - assert(isInSILMode()); - auto loc = leadingTriviaLoc(); - Optional result; - auto status = parseSILGenericParamsSyntax(result); - if (!result.hasValue()) { - status.setIsParseError(); - return status; - } + if (!isInSILMode()) + return parseGenericParameters(); - SyntaxContext->addSyntax(std::move(*result)); - auto list = SyntaxContext->topNode(); - auto ret = Generator.generate(list, loc); - if (!ret) - return nullptr; - return makeParserResult(status, ret); + // In SIL mode, we can have multiple generic parameter lists, with the + // first one being the outmost generic parameter list. + GenericParamList *gpl = nullptr, *outer_gpl = nullptr; + do { + gpl = parseGenericParameters().getPtrOrNull(); + if (!gpl) + return nullptr; + + if (outer_gpl) + gpl->setOuterParameters(outer_gpl); + outer_gpl = gpl; + } while (startsWithLess(Tok)); + return makeParserResult(gpl); } void @@ -242,145 +242,131 @@ Parser::diagnoseWhereClauseInGenericParamList(const GenericParamList * } } -/// Parse a 'where' clause, which places additional constraints on generic -/// parameters or types based on them. +/// parseGenericWhereClause - Parse a 'where' clause, which places additional +/// constraints on generic parameters or types based on them. /// /// where-clause: -/// 'where' generic-requirement (',' generic-requirement) * +/// 'where' requirement (',' requirement) * /// -/// generic-requirement: +/// requirement: /// conformance-requirement /// same-type-requirement -/// layout-requirement /// /// conformance-requirement: -/// type ':' type +/// type-identifier ':' type-identifier +/// type-identifier ':' type-composition /// /// same-type-requirement: -/// type '==' type -/// -/// layout-requirement: -/// type ':' layout-constraint -ParsedSyntaxResult -Parser::parseGenericWhereClauseSyntax(bool &FirstTypeInComplete, - bool allowLayoutConstraints) { - ParsedGenericWhereClauseSyntaxBuilder builder(*SyntaxContext); - ParserStatus status; - - // Parse 'where'. - builder.useWhereKeyword(consumeTokenSyntax(tok::kw_where)); - - bool hasNext = true; +/// type-identifier '==' type +ParserStatus Parser::parseGenericWhereClause( + SourceLoc &WhereLoc, + SmallVectorImpl &Requirements, + bool &FirstTypeInComplete, + bool AllowLayoutConstraints) { + SyntaxParsingContext ClauseContext(SyntaxContext, + SyntaxKind::GenericWhereClause); + ParserStatus Status; + // Parse the 'where'. + WhereLoc = consumeToken(tok::kw_where); + FirstTypeInComplete = false; + SyntaxParsingContext ReqListContext(SyntaxContext, + SyntaxKind::GenericRequirementList); + bool HasNextReq; do { - auto firstType = parseTypeSyntax(); - status |= firstType.getStatus(); - FirstTypeInComplete = firstType.hasCodeCompletion(); - if (firstType.isNull()) - break; + SyntaxParsingContext ReqContext(SyntaxContext, SyntaxContextKind::Syntax); + // Parse the leading type. It doesn't necessarily have to be just a type + // identifier if we're dealing with a same-type constraint. + ParserResult FirstType = parseType(); + + if (FirstType.hasCodeCompletion()) { + Status.setHasCodeCompletion(); + FirstTypeInComplete = true; + } - ParsedGenericRequirementSyntaxBuilder elementBuilder(*SyntaxContext); + if (FirstType.isNull()) { + Status.setIsParseError(); + break; + } if (Tok.is(tok::colon)) { - auto colon = consumeTokenSyntax(tok::colon); - + // A conformance-requirement. + SourceLoc ColonLoc = consumeToken(); + ReqContext.setCreateSyntax(SyntaxKind::ConformanceRequirement); if (Tok.is(tok::identifier) && getLayoutConstraint(Context.getIdentifier(Tok.getText()), Context) ->isKnownLayout()) { - // Layout constraint. - ParsedLayoutRequirementSyntaxBuilder layoutReqBuilder(*SyntaxContext); - layoutReqBuilder.useLeftTypeIdentifier(firstType.get()); - layoutReqBuilder.useColon(std::move(colon)); - SourceLoc layoutLoc = Tok.getLoc(); - auto layout = parseLayoutConstraintSyntax(); - status |= layout.getStatus(); - - if (!allowLayoutConstraints && !isInSILMode()) - diagnose(layoutLoc, + // Parse a layout constraint. + Identifier LayoutName; + auto LayoutLoc = consumeIdentifier(&LayoutName); + auto LayoutInfo = parseLayoutConstraint(LayoutName); + if (!LayoutInfo->isKnownLayout()) { + // There was a bug in the layout constraint. + Status.setIsParseError(); + } + auto Layout = LayoutInfo; + // Types in SIL mode may contain layout constraints. + if (!AllowLayoutConstraints && !isInSILMode()) { + diagnose(LayoutLoc, diag::layout_constraints_only_inside_specialize_attr); - assert(!layout.isNull()); - layoutReqBuilder.useLayoutConstraint(layout.get()); - elementBuilder.useBody(layoutReqBuilder.build()); + } else { + // Add the layout requirement. + Requirements.push_back(RequirementRepr::getLayoutConstraint( + FirstType.get(), ColonLoc, + LayoutConstraintLoc(Layout, LayoutLoc))); + } } else { - // Conformance requirement. - ParsedConformanceRequirementSyntaxBuilder conformanceReqBuilder( - *SyntaxContext); - conformanceReqBuilder.useLeftTypeIdentifier(firstType.get()); - conformanceReqBuilder.useColon(std::move(colon)); - auto secondType = parseTypeSyntax(); - status |= secondType.getStatus(); - if (!secondType.isNull()) - conformanceReqBuilder.useRightTypeIdentifier(secondType.get()); - else - conformanceReqBuilder.useRightTypeIdentifier( - ParsedSyntaxRecorder::makeUnknownType({}, *SyntaxContext)); - elementBuilder.useBody(conformanceReqBuilder.build()); + // Parse the protocol or composition. + ParserResult Protocol = parseType(); + + if (Protocol.isNull()) { + Status.setIsParseError(); + if (Protocol.hasCodeCompletion()) + Status.setHasCodeCompletion(); + break; + } + + // Add the requirement. + Requirements.push_back(RequirementRepr::getTypeConstraint( + FirstType.get(), ColonLoc, Protocol.get())); } } else if ((Tok.isAnyOperator() && Tok.getText() == "==") || Tok.is(tok::equal)) { - // Same type requirement. - ParsedSameTypeRequirementSyntaxBuilder sametypeReqBuilder(*SyntaxContext); - sametypeReqBuilder.useLeftTypeIdentifier(firstType.get()); + ReqContext.setCreateSyntax(SyntaxKind::SameTypeRequirement); + // A same-type-requirement if (Tok.is(tok::equal)) { diagnose(Tok, diag::requires_single_equal) - .fixItReplace(SourceRange(Tok.getLoc()), "=="); - ignoreToken(); - } else { - sametypeReqBuilder.useEqualityToken(consumeTokenSyntax()); + .fixItReplace(SourceRange(Tok.getLoc()), "=="); + } + SourceLoc EqualLoc = consumeToken(); + + // Parse the second type. + ParserResult SecondType = parseType(); + if (SecondType.isNull()) { + Status.setIsParseError(); + if (SecondType.hasCodeCompletion()) + Status.setHasCodeCompletion(); + break; } - auto secondType = parseTypeSyntax(); - status |= secondType.getStatus(); - if (!secondType.isNull()) - sametypeReqBuilder.useRightTypeIdentifier(secondType.get()); - else - sametypeReqBuilder.useRightTypeIdentifier( - ParsedSyntaxRecorder::makeUnknownType({}, *SyntaxContext)); - elementBuilder.useBody(sametypeReqBuilder.build()); + // Add the requirement + Requirements.push_back(RequirementRepr::getSameType(FirstType.get(), + EqualLoc, + SecondType.get())); } else { diagnose(Tok, diag::expected_requirement_delim); - status.setIsParseError(); - - // Fallback to conformance requirement with missing right type. - ParsedConformanceRequirementSyntaxBuilder conformanceReqBuilder( - *SyntaxContext); - conformanceReqBuilder.useLeftTypeIdentifier(firstType.get()); - conformanceReqBuilder.useRightTypeIdentifier( - ParsedSyntaxRecorder::makeUnknownType({}, *SyntaxContext)); - elementBuilder.useBody(conformanceReqBuilder.build()); + Status.setIsParseError(); + break; } + HasNextReq = consumeIf(tok::comma); + // If there's a comma, keep parsing the list. + } while (HasNextReq); - // Parse ','. - hasNext = (status.isSuccess() && Tok.is(tok::comma)); - if (hasNext) - elementBuilder.useTrailingComma(consumeTokenSyntax()); - - builder.addRequirementListMember(elementBuilder.build()); - } while (hasNext && status.isSuccess()); + if (Requirements.empty()) + WhereLoc = SourceLoc(); - return makeParsedResult(builder.build(), status); + return Status; } -ParserStatus Parser::parseGenericWhereClause( - SourceLoc &whereLoc, SmallVectorImpl &requirements, - bool &FirstTypeInComplete, bool AllowLayoutConstraints) { - auto loc = leadingTriviaLoc(); - auto syntaxResult = parseGenericWhereClauseSyntax(FirstTypeInComplete, - AllowLayoutConstraints); - if (syntaxResult.isNull()) - return syntaxResult.getStatus(); - - SyntaxContext->addSyntax(syntaxResult.get()); - auto clause = SyntaxContext->topNode(); - - whereLoc = Generator.generate(clause.getWhereKeyword(), loc); - requirements.reserve(clause.getRequirementList().size()); - for (auto elem : clause.getRequirementList()) { - if (auto req = Generator.generate(elem, loc)) - requirements.push_back(*req); - } - - return syntaxResult.getStatus(); -} /// Parse a free-standing where clause attached to a declaration, adding it to /// a generic parameter list that may (or may not) already exist. diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index f6542b3da80b1..7b4eaf46862a9 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -61,61 +61,81 @@ TypeRepr *Parser::applyAttributeToType(TypeRepr *ty, return ty; } -/// Parse layout constraint for 'where' clause in '@_specialize' attribute -/// and in SIL. -/// -/// layout-constraint: -/// identifier -/// identifier '(' integer-literal ')' -/// identifier '(' integer-literal ',' integer-literal ')' -ParsedSyntaxResult -Parser::parseLayoutConstraintSyntax() { - assert(Tok.is(tok::identifier)); - ParsedLayoutConstraintSyntaxBuilder builder(*SyntaxContext); - - builder.useName(consumeTokenSyntax(tok::identifier)); - - if (!Tok.isFollowingLParen()) - return makeParsedResult(builder.build()); - - auto lParenLoc = Tok.getLoc(); - builder.useLeftParen(consumeTokenSyntax(tok::l_paren)); - - auto parseTrivialConstraintBody = [&]() -> bool { - int value; - - if (!Tok.is(tok::integer_literal) || - Tok.getText().getAsInteger(10, value) || value < 0) { - diagnose(Tok, diag::layout_size_should_be_positive); - return true; - } - builder.useSize(consumeTokenSyntax(tok::integer_literal)); +LayoutConstraint Parser::parseLayoutConstraint(Identifier LayoutConstraintID) { + LayoutConstraint layoutConstraint = + getLayoutConstraint(LayoutConstraintID, Context); + assert(layoutConstraint->isKnownLayout() && + "Expected layout constraint definition"); + + if (!layoutConstraint->isTrivial()) + return layoutConstraint; + + SourceLoc LParenLoc; + if (!consumeIf(tok::l_paren, LParenLoc)) { + // It is a trivial without any size constraints. + return LayoutConstraint::getLayoutConstraint(LayoutConstraintKind::Trivial, + Context); + } - if (Tok.is(tok::comma)) { - builder.useComma(consumeTokenSyntax(tok::comma)); + int size = 0; + int alignment = 0; - if (!Tok.is(tok::integer_literal) || - Tok.getText().getAsInteger(10, value) || value < 0) { - diagnose(Tok, diag::layout_alignment_should_be_positive); + auto ParseTrivialLayoutConstraintBody = [&] () -> bool { + // Parse the size and alignment. + if (Tok.is(tok::integer_literal)) { + if (Tok.getText().getAsInteger(10, size)) { + diagnose(Tok.getLoc(), diag::layout_size_should_be_positive); return true; } - builder.useAlignment(consumeTokenSyntax(tok::integer_literal)); + consumeToken(); + if (consumeIf(tok::comma)) { + // parse alignment. + if (Tok.is(tok::integer_literal)) { + if (Tok.getText().getAsInteger(10, alignment)) { + diagnose(Tok.getLoc(), diag::layout_alignment_should_be_positive); + return true; + } + consumeToken(); + } else { + diagnose(Tok.getLoc(), diag::layout_alignment_should_be_positive); + return true; + } + } + } else { + diagnose(Tok.getLoc(), diag::layout_size_should_be_positive); + return true; } return false; }; - if (parseTrivialConstraintBody()) { - ignoreUntil(tok::r_paren); - if (Tok.is(tok::r_paren)) - builder.useRightParen(consumeTokenSyntax(tok::r_paren)); - } else { - auto rParen = parseMatchingTokenSyntax(tok::r_paren, - diag::expected_rparen_layout_constraint, - lParenLoc); - if (rParen) - builder.useRightParen(std::move(*rParen)); + if (ParseTrivialLayoutConstraintBody()) { + // There was an error during parsing. + skipUntil(tok::r_paren); + consumeIf(tok::r_paren); + return LayoutConstraint::getUnknownLayout(); } - return makeParsedResult(builder.build()); + + if (!consumeIf(tok::r_paren)) { + // Expected a closing r_paren. + diagnose(Tok.getLoc(), diag::expected_rparen_layout_constraint); + consumeToken(); + return LayoutConstraint::getUnknownLayout(); + } + + if (size < 0) { + diagnose(Tok.getLoc(), diag::layout_size_should_be_positive); + return LayoutConstraint::getUnknownLayout(); + } + + if (alignment < 0) { + diagnose(Tok.getLoc(), diag::layout_alignment_should_be_positive); + return LayoutConstraint::getUnknownLayout(); + } + + // Otherwise it is a trivial layout constraint with + // provided size and alignment. + return LayoutConstraint::getLayoutConstraint(layoutConstraint->getKind(), size, + alignment, Context); } /// parseTypeSimple @@ -349,7 +369,7 @@ Parser::TypeASTResult Parser::parseType(Diag<> MessageID, // the function body; otherwise, they are visible when parsing the type. if (!IsSILFuncDecl) GenericsScope.emplace(this, ScopeKind::Generics); - generics = parseSILGenericParams().getPtrOrNull(); + generics = maybeParseGenericParams().getPtrOrNull(); } // In SIL mode, parse box types { ... }. diff --git a/lib/Parse/ParsedSyntaxBuilders.cpp.gyb b/lib/Parse/ParsedSyntaxBuilders.cpp.gyb index 9306c0c8902f1..9ab3964f2b2cb 100644 --- a/lib/Parse/ParsedSyntaxBuilders.cpp.gyb +++ b/lib/Parse/ParsedSyntaxBuilders.cpp.gyb @@ -26,7 +26,7 @@ using namespace swift; using namespace swift::syntax; -% for node in SYNTAX_NODES + SILONLY_NODES: +% for node in SYNTAX_NODES: % if node.is_buildable(): % for child in node.children: % child_elt = None diff --git a/lib/Parse/ParsedSyntaxNodes.cpp.gyb b/lib/Parse/ParsedSyntaxNodes.cpp.gyb index a21a0674a39e1..e3bb56c91812e 100644 --- a/lib/Parse/ParsedSyntaxNodes.cpp.gyb +++ b/lib/Parse/ParsedSyntaxNodes.cpp.gyb @@ -23,7 +23,7 @@ using namespace swift; using namespace swift::syntax; -% for node in SYNTAX_NODES + SILONLY_NODES: +% for node in SYNTAX_NODES: % for child in node.children: % if child.is_optional: Optional diff --git a/lib/Parse/ParsedSyntaxRecorder.cpp.gyb b/lib/Parse/ParsedSyntaxRecorder.cpp.gyb index 1e62ea13ba721..b305e25e7cc8f 100644 --- a/lib/Parse/ParsedSyntaxRecorder.cpp.gyb +++ b/lib/Parse/ParsedSyntaxRecorder.cpp.gyb @@ -29,7 +29,7 @@ bool ParsedSyntaxRecorder::formExactLayoutFor(syntax::SyntaxKind Kind, MutableArrayRef Elements, function_ref)> receiver) { switch (Kind) { -% for node in SYNTAX_NODES + SILONLY_NODES: +% for node in SYNTAX_NODES: case SyntaxKind::${node.syntax_kind}: { % if node.children: % child_count = len(node.children) @@ -77,7 +77,7 @@ bool ParsedSyntaxRecorder::formExactLayoutFor(syntax::SyntaxKind Kind, } } -% for node in SYNTAX_NODES + SILONLY_NODES: +% for node in SYNTAX_NODES: % if node.children: % child_params = [] % child_move_args = [] diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 7980fd39f1006..f25a65fa096ef 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -527,7 +527,7 @@ Parser::Parser(std::unique_ptr Lex, SourceFile &SF, L->getBufferID(), SF.SyntaxParsingCache, SF.getASTContext().getSyntaxArena())))), - Generator(SF.getASTContext(), *this) { + Generator(SF.getASTContext(), &State) { State = PersistentState; if (!State) { OwnedState.reset(new PersistentParserState()); diff --git a/lib/ParseSIL/ParseSIL.cpp b/lib/ParseSIL/ParseSIL.cpp index 5915ef23758e6..cededafc650aa 100644 --- a/lib/ParseSIL/ParseSIL.cpp +++ b/lib/ParseSIL/ParseSIL.cpp @@ -3115,7 +3115,7 @@ bool SILParser::parseSILInstruction(SILBuilder &B) { SmallVector operandTypes; { Scope genericsScope(&P, ScopeKind::Generics); - generics = P.parseSILGenericParams().getPtrOrNull(); + generics = P.maybeParseGenericParams().getPtrOrNull(); patternEnv = handleSILGenericParams(P.Context, generics, &P.SF); if (P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "(")) @@ -5720,7 +5720,7 @@ bool SILParserTUState::parseSILProperty(Parser &P) { GenericEnvironment *patternEnv; Scope toplevelScope(&P, ScopeKind::TopLevel); Scope genericsScope(&P, ScopeKind::Generics); - generics = P.parseSILGenericParams().getPtrOrNull(); + generics = P.maybeParseGenericParams().getPtrOrNull(); patternEnv = handleSILGenericParams(P.Context, generics, &P.SF); if (patternEnv) { @@ -6033,7 +6033,7 @@ Optional SILParser::parseProtocolConformance( // Make sure we don't leave it uninitialized in the caller genericEnv = nullptr; - auto *genericParams = P.parseSILGenericParams().getPtrOrNull(); + auto *genericParams = P.maybeParseGenericParams().getPtrOrNull(); if (genericParams) { genericEnv = handleSILGenericParams(P.Context, genericParams, &P.SF); } diff --git a/lib/Syntax/SyntaxBuilders.cpp.gyb b/lib/Syntax/SyntaxBuilders.cpp.gyb index 3a3af38751078..8c93726dc5123 100644 --- a/lib/Syntax/SyntaxBuilders.cpp.gyb +++ b/lib/Syntax/SyntaxBuilders.cpp.gyb @@ -25,7 +25,7 @@ using namespace swift; using namespace swift::syntax; -% for node in SYNTAX_NODES + SILONLY_NODES: +% for node in SYNTAX_NODES: % if node.is_buildable(): % for child in node.children: ${node.name}Builder & diff --git a/lib/Syntax/SyntaxFactory.cpp.gyb b/lib/Syntax/SyntaxFactory.cpp.gyb index f7652bd83b5f8..dc6ad1a8c90dd 100644 --- a/lib/Syntax/SyntaxFactory.cpp.gyb +++ b/lib/Syntax/SyntaxFactory.cpp.gyb @@ -63,7 +63,7 @@ SyntaxFactory::makeUnknownSyntax(llvm::ArrayRef Tokens, Syntax SyntaxFactory::makeBlankCollectionSyntax(SyntaxKind Kind) { switch(Kind) { -% for node in SYNTAX_NODES + SILONLY_NODES: +% for node in SYNTAX_NODES: % if node.is_syntax_collection(): case SyntaxKind::${node.syntax_kind}: return makeBlank${node.syntax_kind}(); % end @@ -76,7 +76,7 @@ Syntax SyntaxFactory::makeBlankCollectionSyntax(SyntaxKind Kind) { std::pair SyntaxFactory::countChildren(SyntaxKind Kind){ switch(Kind) { -% for node in SYNTAX_NODES + SILONLY_NODES: +% for node in SYNTAX_NODES: % if not node.is_syntax_collection(): case SyntaxKind::${node.syntax_kind}: % child_count = len(node.children) @@ -92,7 +92,7 @@ SyntaxFactory::countChildren(SyntaxKind Kind){ bool SyntaxFactory::canServeAsCollectionMemberRaw(SyntaxKind CollectionKind, SyntaxKind MemberKind) { switch (CollectionKind) { -% for node in SYNTAX_NODES + SILONLY_NODES: +% for node in SYNTAX_NODES: % if node.is_syntax_collection(): case SyntaxKind::${node.syntax_kind}: % if node.collection_element_choices: @@ -125,7 +125,7 @@ RC SyntaxFactory::createRaw(SyntaxKind Kind, llvm::ArrayRef> Elements, RC Arena) { switch (Kind) { -% for node in SYNTAX_NODES + SILONLY_NODES: +% for node in SYNTAX_NODES: case SyntaxKind::${node.syntax_kind}: { % if node.children: % child_count = len(node.children) @@ -178,7 +178,7 @@ Optional SyntaxFactory::createSyntax(SyntaxKind Kind, return None; } -% for node in SYNTAX_NODES + SILONLY_NODES: +% for node in SYNTAX_NODES: % if node.children: % child_params = [] % for child in node.children: diff --git a/lib/Syntax/SyntaxKind.cpp.gyb b/lib/Syntax/SyntaxKind.cpp.gyb index 811c02ba3b14c..7603508970385 100644 --- a/lib/Syntax/SyntaxKind.cpp.gyb +++ b/lib/Syntax/SyntaxKind.cpp.gyb @@ -52,7 +52,7 @@ bool isTokenKeyword(tok kind) { bool parserShallOmitWhenNoChildren(syntax::SyntaxKind Kind) { switch(Kind) { -% for node in SYNTAX_NODES + SILONLY_NODES: +% for node in SYNTAX_NODES: % if node.shall_be_omitted_when_empty(): case syntax::SyntaxKind::${node.syntax_kind}: % end @@ -73,7 +73,7 @@ void dumpSyntaxKind(llvm::raw_ostream &os, const SyntaxKind kind) { case SyntaxKind::Unknown: os << "Unknown"; break; -% for node in SYNTAX_NODES + SILONLY_NODES: +% for node in SYNTAX_NODES: case SyntaxKind::${node.syntax_kind}: os << "${node.syntax_kind}"; break; @@ -83,7 +83,7 @@ void dumpSyntaxKind(llvm::raw_ostream &os, const SyntaxKind kind) { bool isCollectionKind(SyntaxKind Kind) { switch(Kind) { -% for node in SYNTAX_NODES + SILONLY_NODES: +% for node in SYNTAX_NODES: % if node.is_syntax_collection(): case SyntaxKind::${node.syntax_kind}: % end @@ -147,7 +147,7 @@ SyntaxKind getUnknownKind(SyntaxKind Kind) { llvm::raw_ostream &llvm::operator<<(llvm::raw_ostream &OS, swift::syntax::SyntaxKind Kind) { switch (Kind) { -% for node in SYNTAX_NODES + SILONLY_NODES: +% for node in SYNTAX_NODES: case swift::syntax::SyntaxKind::${node.syntax_kind}: OS << "${node.syntax_kind}"; break; diff --git a/lib/Syntax/SyntaxNodes.cpp.gyb b/lib/Syntax/SyntaxNodes.cpp.gyb index e3302f3389914..34418e182f1ca 100644 --- a/lib/Syntax/SyntaxNodes.cpp.gyb +++ b/lib/Syntax/SyntaxNodes.cpp.gyb @@ -24,7 +24,7 @@ using namespace swift; using namespace swift::syntax; -% for node in SYNTAX_NODES + SILONLY_NODES: +% for node in SYNTAX_NODES: % if node.requires_validation(): void ${node.name}::validate() const { #ifndef NDEBUG diff --git a/lib/Syntax/SyntaxVisitor.cpp.gyb b/lib/Syntax/SyntaxVisitor.cpp.gyb index 14e92d72c1995..722ab5d46f4e7 100644 --- a/lib/Syntax/SyntaxVisitor.cpp.gyb +++ b/lib/Syntax/SyntaxVisitor.cpp.gyb @@ -21,7 +21,7 @@ #include "swift/Syntax/SyntaxVisitor.h" #include "swift/Basic/Defer.h" -% for node in SYNTAX_NODES + SILONLY_NODES: +% for node in SYNTAX_NODES: % if is_visitable(node): void swift::syntax::SyntaxVisitor::visit(${node.name} node) { visitChildren(node); @@ -36,7 +36,7 @@ void swift::syntax::SyntaxVisitor::visit(Syntax node) { case SyntaxKind::Token: visit(node.castTo()); return; -% for node in SYNTAX_NODES + SILONLY_NODES: +% for node in SYNTAX_NODES: % if is_visitable(node): case SyntaxKind::${node.syntax_kind}: visit(node.castTo<${node.name}>()); diff --git a/test/Parse/invalid.swift b/test/Parse/invalid.swift index 097588b54f695..7a290d5c8b669 100644 --- a/test/Parse/invalid.swift +++ b/test/Parse/invalid.swift @@ -124,7 +124,7 @@ prefix func %(x: T) -> T { return x } // No error expected - the < is conside struct Weak { // expected-error {{'class' constraint can only appear on protocol declarations}} // expected-note@-1 {{did you mean to write an 'AnyObject' constraint?}} {{16-21=AnyObject}} - weak let value: T // expected-error {{'weak' must be a mutable variable, because it may change at runtime}} expected-error {{'weak' variable should have optional type 'T?'}} + weak let value: T // expected-error {{'weak' must be a mutable variable, because it may change at runtime}} expected-error {{'weak' variable should have optional type 'T?'}} expected-error {{'weak' must not be applied to non-class-bound 'T'; consider adding a protocol conformance that has a class bound}} } let x: () = () diff --git a/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds b/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds index 680d7b2d4cae4..6a687bae4e8c9 100644 --- a/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds +++ b/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds @@ -121,7 +121,7 @@ protocol PP { associatedtype B: Sequence associatedtype C = Int associatedtype D: Sequence = [Int] - associatedtype E: Sequence = [[Int]] where A.Element : Sequence + associatedtype E: Sequence = [[Int]] where A.Element : Sequence private associatedtype F @objc associatedtype G } @@ -155,7 +155,7 @@ class Bar: Foo foo: Int = 42 } -class C<A, B> where A: Foo, B == Bar {} +class C<A, B> where A: Foo, B == Bar {} @available(*, unavailable) private class C {} @@ -183,9 +183,9 @@ struct foo { } } -struct S<A, B, C, @objc D> where A:B, B==C, A : C, B.C == D.A, A.B: C.D {} +struct S<A, B, C, @objc D> where A:B, B==C, A : C, B.C == D.A, A.B: C.D {} -private struct S<A, B>: Base where A: B { +private struct S<A, B>: Base where A: B { private struct S: A, B {} } @@ -205,18 +205,18 @@ func foo( a: { @objc @available(*, unavailable) -private static override func foo<a, b, c>(a b: Int, c: Int) throws -> [Int] where a==p1, b:p2 { ddd } +private static override func foo<a, b, c>(a b: Int, c: Int) throws -> [Int] where a==p1, b:p2 { ddd } func rootView() -> Label {} static func ==() -> bool {} static func !=<a, b, c>() -> bool {} } @objc -private protocol foo : bar where A==B {} +private protocol foo : bar where A==B {} protocol foo { func foo() } private protocol foo{} @objc -public protocol foo where A:B {} +public protocol foo where A:B {} #if blah func tryfoo() { @@ -431,7 +431,7 @@ fileprivate extension ext ext : extProtocol {} -extension ext where A == Int, B: Numeric {} +extension ext where A == Int, B: Numeric {} extension ext.a.b {} @@ -478,7 +478,7 @@ enum E1 : String bar = "test", baz(x: Int, String) = 12 indirect case qux(E1) - indirect private enum E2<T>: String where T: SomeProtocol { + indirect private enum E2<T>: String where T: SomeProtocol { case foo, bar, baz } } @@ -507,8 +507,8 @@ func higherOrderFunc() #available(iOS 11, macOS 10.11.2, *) {} -@_specialize(where T == Int) -@_specialize(exported: true, where T == String) +@_specialize(where T == Int) +@_specialize(exported: true, where T == String) public func specializedGenericFunc<T>(_ t: T) -> T { return t } diff --git a/unittests/Syntax/DeclSyntaxTests.cpp b/unittests/Syntax/DeclSyntaxTests.cpp index bc13978633314..5f29d564442fa 100644 --- a/unittests/Syntax/DeclSyntaxTests.cpp +++ b/unittests/Syntax/DeclSyntaxTests.cpp @@ -550,11 +550,11 @@ GenericWhereClauseSyntax getCannedWhereClause() { auto T = SyntaxFactory::makeTypeIdentifier("T", {}, Trivia::spaces(1)); auto EqualEqual = SyntaxFactory::makeEqualityOperator({}, Trivia::spaces(1)); auto Int = SyntaxFactory::makeTypeIdentifier("Int", {}, Trivia::spaces(1)); - auto SameType = SyntaxFactory::makeSameTypeRequirement(T, EqualEqual, Int); - auto Req = SyntaxFactory::makeGenericRequirement(SameType, None); + auto SameType = SyntaxFactory::makeSameTypeRequirement(T, EqualEqual, Int, + None); auto Requirements = SyntaxFactory::makeBlankGenericRequirementList() - .appending(Req); + .appending(SameType); return SyntaxFactory::makeBlankGenericWhereClause() .withWhereKeyword(WhereKW) diff --git a/utils/gyb_syntax_support/GenericNodes.py b/utils/gyb_syntax_support/GenericNodes.py index afb6a4af2e99d..e93a80b3bfe05 100644 --- a/utils/gyb_syntax_support/GenericNodes.py +++ b/utils/gyb_syntax_support/GenericNodes.py @@ -11,39 +11,22 @@ ]), Node('GenericRequirementList', kind='SyntaxCollection', - element='GenericRequirement', + element='Syntax', element_name='GenericRequirement'), - # generic-requirement -> - # (same-type-requrement|conformance-requirement|layout-requirement) ','? - Node('GenericRequirement', kind='Syntax', - traits=['WithTrailingComma'], - children=[ - Child('Body', kind='Syntax', - node_choices=[ - Child('SameTypeRequirement', - kind='SameTypeRequirement'), - Child('ConformanceRequirement', - kind='ConformanceRequirement'), - Child('LayoutRequirement', - kind='LayoutRequirement'), - ]), - Child('TrailingComma', kind='CommaToken', - is_optional=True), - ]), - # same-type-requirement -> type-identifier == type Node('SameTypeRequirement', kind='Syntax', + traits=['WithTrailingComma'], children=[ Child('LeftTypeIdentifier', kind='Type'), Child('EqualityToken', kind='Token', token_choices=[ 'SpacedBinaryOperatorToken', 'UnspacedBinaryOperatorToken', - 'PrefixOperatorToken', - 'PostfixOperatorToken', ]), Child('RightTypeIdentifier', kind='Type'), + Child('TrailingComma', kind='CommaToken', + is_optional=True), ]), Node('GenericParameterList', kind='SyntaxCollection', @@ -72,41 +55,17 @@ Child('LeftAngleBracket', kind='LeftAngleToken'), Child('GenericParameterList', kind='GenericParameterList', collection_element_name='GenericParameter'), - Child('ObsoletedWhereClause', kind='GenericWhereClause', - is_optional=True), Child('RightAngleBracket', kind='RightAngleToken'), ]), # conformance-requirement -> type-identifier : type-identifier Node('ConformanceRequirement', kind='Syntax', + traits=['WithTrailingComma'], children=[ Child('LeftTypeIdentifier', kind='Type'), Child('Colon', kind='ColonToken'), Child('RightTypeIdentifier', kind='Type'), - ]), - - # layout-requirement -> type ':' layout-constraint - Node('LayoutRequirement', kind='Syntax', - children=[ - Child('LeftTypeIdentifier', kind='Type'), - Child('Colon', kind='ColonToken'), - Child('LayoutConstraint', kind='LayoutConstraint'), - ]), - - # layout-constraint -> - # identifier ('(' integer-literal (',' integer-literal)? ')')? - Node('LayoutConstraint', kind='Syntax', - children=[ - Child('Name', kind='IdentifierToken'), - Child('LeftParen', kind='LeftParenToken', - is_optional=True), - Child('Size', kind='IntegerLiteralToken', - is_optional=True), - Child('Comma', kind='CommaToken', - is_optional=True), - Child('Alignment', kind='IntegerLiteralToken', - is_optional=True), - Child('RightParen', kind='RightParenToken', - is_optional=True), + Child('TrailingComma', kind='CommaToken', + is_optional=True), ]), ] diff --git a/utils/gyb_syntax_support/NodeSerializationCodes.py b/utils/gyb_syntax_support/NodeSerializationCodes.py index fb9edd7ca3e40..4bacc660f7cbc 100644 --- a/utils/gyb_syntax_support/NodeSerializationCodes.py +++ b/utils/gyb_syntax_support/NodeSerializationCodes.py @@ -233,9 +233,6 @@ 'PoundAssertStmt': 229, 'SomeType': 230, 'CustomAttribute': 231, - 'GenericRequirement': 232, - 'LayoutRequirement': 233, - 'LayoutConstraint': 234, } diff --git a/utils/gyb_syntax_support/SILOnlyNodes.py b/utils/gyb_syntax_support/SILOnlyNodes.py deleted file mode 100644 index 799ca5c99ee56..0000000000000 --- a/utils/gyb_syntax_support/SILOnlyNodes.py +++ /dev/null @@ -1,9 +0,0 @@ -from Node import Node # noqa: I201 - -# These nodes are used only in SIL parsing. - -SILONLY_NODES = [ - # generic-parameter-clause-list - Node('GenericParameterClauseList', kind='SyntaxCollection', - element='GenericParameterClause'), -] diff --git a/utils/gyb_syntax_support/__init__.py b/utils/gyb_syntax_support/__init__.py index 437ce147b321c..6f32da7920fa7 100644 --- a/utils/gyb_syntax_support/__init__.py +++ b/utils/gyb_syntax_support/__init__.py @@ -11,7 +11,6 @@ verify_syntax_node_serialization_codes from PatternNodes import PATTERN_NODES # noqa: I201 -from SILOnlyNodes import SILONLY_NODES # noqa: I201 from StmtNodes import STMT_NODES # noqa: I201 import Token from Trivia import TRIVIAS # noqa: I201 From d395eb18ae1b170721e058f610e8252a9fc47c52 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 20 Sep 2019 16:13:07 -0400 Subject: [PATCH 113/199] AST: Remove LazyResolver::resolveProtocolEnvironment() --- include/swift/AST/LazyResolver.h | 3 --- lib/Sema/TypeCheckType.cpp | 9 --------- lib/Sema/TypeChecker.h | 4 ---- 3 files changed, 16 deletions(-) diff --git a/include/swift/AST/LazyResolver.h b/include/swift/AST/LazyResolver.h index 9a6b298a40265..be8a01bc911ca 100644 --- a/include/swift/AST/LazyResolver.h +++ b/include/swift/AST/LazyResolver.h @@ -60,9 +60,6 @@ class LazyResolver { /// consistency and provides the value a type. virtual void resolveDeclSignature(ValueDecl *VD) = 0; - /// Resolve the generic environment of the given protocol. - virtual void resolveProtocolEnvironment(ProtocolDecl *proto) = 0; - /// Resolve the type of an extension. /// /// This can be called to ensure that the members of an extension can be diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index bd3cae670a384..837a8137c4cfa 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -3445,15 +3445,6 @@ Type TypeChecker::substMemberTypeWithBase(ModuleDecl *module, aliasDecl, baseTy, aliasDecl->getASTContext()); } - - // FIXME: If this is a protocol typealias and we haven't built the - // protocol's generic environment yet, do so now, to ensure the - // typealias's underlying type has fully resolved dependent - // member types. - if (auto *protoDecl = dyn_cast(aliasDecl->getDeclContext())) { - ASTContext &ctx = protoDecl->getASTContext(); - ctx.getLazyResolver()->resolveProtocolEnvironment(protoDecl); - } } Type resultType; diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 877d6deddd9bc..e0055726f9186 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -1013,10 +1013,6 @@ class TypeChecker final : public LazyResolver { validateDecl(VD); } - virtual void resolveProtocolEnvironment(ProtocolDecl *proto) override { - validateDecl(proto); - } - virtual void resolveExtension(ExtensionDecl *ext) override { validateExtension(ext); } From b3f43680d8f8b3dfab5bca0ad5ae09ff522b05d1 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 20 Sep 2019 14:26:39 -0400 Subject: [PATCH 114/199] AST: Simplify SubstitutionMap::getProtocolSubstitutions() --- lib/AST/SubstitutionMap.cpp | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/lib/AST/SubstitutionMap.cpp b/lib/AST/SubstitutionMap.cpp index 8d06996328269..acab31b997bdb 100644 --- a/lib/AST/SubstitutionMap.cpp +++ b/lib/AST/SubstitutionMap.cpp @@ -486,27 +486,9 @@ SubstitutionMap SubstitutionMap::getProtocolSubstitutions(ProtocolDecl *protocol, Type selfType, ProtocolConformanceRef conformance) { - auto protocolSelfType = protocol->getSelfInterfaceType(); - - return get( - protocol->getGenericSignature(), - [&](SubstitutableType *type) -> Type { - if (type->isEqual(protocolSelfType)) - return selfType; - - // This will need to change if we ever support protocols - // inside generic types. - return Type(); - }, - [&](CanType origType, Type replacementType, ProtocolDecl *protoType) - -> Optional { - if (origType->isEqual(protocolSelfType) && protoType == protocol) - return conformance; - - // This will need to change if we ever support protocols - // inside generic types. - return None; - }); + return get(protocol->getGenericSignature(), + llvm::makeArrayRef(selfType), + llvm::makeArrayRef(conformance)); } SubstitutionMap From 9a454d4fe8911803e4cb856e6bbc6d41d2d508ea Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 20 Sep 2019 15:17:43 -0400 Subject: [PATCH 115/199] AST: Clean up ASTVerifier's archetype verification a bit --- lib/AST/ASTVerifier.cpp | 47 ++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp index 67cdb1befe200..1f047fac12380 100644 --- a/lib/AST/ASTVerifier.cpp +++ b/lib/AST/ASTVerifier.cpp @@ -176,22 +176,6 @@ template T *getOverriddenDeclIfAvailable(T *decl) { return cast_or_null(decl->getOverriddenDecl()); } - -// Retrieve the generic signature of the innermost context that has been forced -// so far. -// -// This avoids kicking off the request for a generic signature in the verifier. -static GenericSignature * -getNearestForcedGenericSignatureOfContext(DeclContext *dc) { - do { - if (auto decl = dc->getAsDecl()) - if (auto GC = decl->getAsGenericContext()) - if (GC->hasComputedGenericSignature()) - return GC->getGenericSignature(); - } while ((dc = dc->getParent())); - - return nullptr; -} } // namespace class Verifier : public ASTWalker { @@ -208,8 +192,9 @@ class Verifier : public ASTWalker { using ScopeLike = llvm::PointerUnion; SmallVector Scopes; - /// The stack of context generic signatures. - SmallVector GenericSig; + /// The stack of generic contexts. + using GenericLike = llvm::PointerUnion; + SmallVector Generics; /// The stack of optional evaluations active at this point. SmallVector OptionalEvaluations; @@ -632,7 +617,7 @@ class Verifier : public ASTWalker { } // Otherwise, the archetype needs to be from this scope. - if (GenericSig.empty() || !GenericSig.back()) { + if (Generics.empty() || !Generics.back()) { Out << "AST verification error: archetype outside of generic " "context: " << root->getString() << "\n"; return true; @@ -643,13 +628,20 @@ class Verifier : public ASTWalker { auto *archetypeEnv = rootPrimary->getGenericEnvironment(); auto *archetypeSig = archetypeEnv->getGenericSignature(); - if (GenericSig.back() != archetypeSig) { + auto genericCtx = Generics.back(); + GenericSignature *genericSig; + if (auto *genericDC = genericCtx.dyn_cast()) + genericSig = genericDC->getGenericSignatureOfContext(); + else + genericSig = genericCtx.get(); + + if (genericSig != archetypeSig) { Out << "Archetype " << root->getString() << " not allowed " << "in this context\n"; Out << "Archetype generic signature: " << archetypeSig->getAsString() << "\n"; Out << "Context generic signature: " - << GenericSig.back()->getAsString() << "\n"; + << genericSig->getAsString() << "\n"; return true; } @@ -704,16 +696,16 @@ class Verifier : public ASTWalker { void pushScope(DeclContext *scope) { Scopes.push_back(scope); - GenericSig.push_back(::getNearestForcedGenericSignatureOfContext(scope)); + Generics.push_back(scope); } void pushScope(BraceStmt *scope) { Scopes.push_back(scope); } void popScope(DeclContext *scope) { assert(Scopes.back().get() == scope); - assert(GenericSig.back() == ::getNearestForcedGenericSignatureOfContext(scope)); + assert(Generics.back().get() == scope); Scopes.pop_back(); - GenericSig.pop_back(); + Generics.pop_back(); } void popScope(BraceStmt *scope) { assert(Scopes.back().get() == scope); @@ -2687,14 +2679,15 @@ class Verifier : public ASTWalker { const auto &witness = normal->getWitness(req); if (auto *genericEnv = witness.getSyntheticEnvironment()) - GenericSig.push_back(genericEnv->getGenericSignature()); + Generics.push_back(genericEnv->getGenericSignature()); verifyChecked(witness.getRequirementToSyntheticSubs()); verifyChecked(witness.getSubstitutions()); if (auto *genericEnv = witness.getSyntheticEnvironment()) { - assert(GenericSig.back() == genericEnv->getGenericSignature()); - GenericSig.pop_back(); + assert(Generics.back().get() + == genericEnv->getGenericSignature()); + Generics.pop_back(); } continue; From 542d255b32fa8a2a59702ca8b05c3ae0df1e95d2 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 20 Sep 2019 15:10:41 -0400 Subject: [PATCH 116/199] AST: ProtocolConformanceRef::subst() returns an invalid conformance instead of trapping This is for consistency with Type::subst() which returns ErrorTypes. --- lib/AST/ProtocolConformance.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/AST/ProtocolConformance.cpp b/lib/AST/ProtocolConformance.cpp index e96a93bc70d18..d26e50009a855 100644 --- a/lib/AST/ProtocolConformance.cpp +++ b/lib/AST/ProtocolConformance.cpp @@ -128,10 +128,12 @@ ProtocolConformanceRef::subst(Type origType, // If the type is an existential, it must be self-conforming. if (substType->isExistentialType()) { - auto optConformance = - proto->getModuleContext()->lookupExistentialConformance(substType, proto); - assert(optConformance && "existential type didn't self-conform"); - return *optConformance; + if (auto optConformance = + proto->getModuleContext()->lookupExistentialConformance( + substType, proto)) + return *optConformance; + + return ProtocolConformanceRef::forInvalid(); } // Check the conformance map. @@ -140,7 +142,7 @@ ProtocolConformanceRef::subst(Type origType, return *result; } - llvm_unreachable("Invalid conformance substitution"); + return ProtocolConformanceRef::forInvalid(); } ProtocolConformanceRef ProtocolConformanceRef::mapConformanceOutOfContext() const { From 4aea87535e50db4d32c1ec7078bf8356e25c6ca3 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 11 Sep 2019 19:43:49 -0400 Subject: [PATCH 117/199] Sema: Add a FIXME comment for a problem I found by inspection I believe this is related to and . --- lib/Sema/TypeCheckProtocol.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index ce434f7f7635d..ea05d1a83dbb3 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -3405,6 +3405,8 @@ CheckTypeWitnessResult swift::checkTypeWitness(TypeChecker &tc, DeclContext *dc, Type contextType = type->hasTypeParameter() ? dc->mapTypeIntoContext(type) : type; + // FIXME: This is incorrect; depTy is written in terms of the protocol's + // associated types, and we need to substitute in known type witnesses. if (auto superclass = genericSig->getSuperclassBound(depTy)) { if (!superclass->isExactSuperclassOf(contextType)) return superclass; From 8f346a0ca8b714de8103b9b05d6020e4645cc0bf Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 20 Sep 2019 15:48:07 -0400 Subject: [PATCH 118/199] IDE: Pick off another usage of isConvertibleTo() with openArchetypes=true --- lib/IDE/IDETypeChecking.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/IDE/IDETypeChecking.cpp b/lib/IDE/IDETypeChecking.cpp index 0a609a2fb480a..dd281397da363 100644 --- a/lib/IDE/IDETypeChecking.cpp +++ b/lib/IDE/IDETypeChecking.cpp @@ -304,15 +304,17 @@ struct SynthesizedExtensionAnalyzer::Implementation { } switch (Kind) { - case RequirementKind::Conformance: - // FIXME: This could be more accurate; check - // conformance instead of subtyping - if (!isConvertibleTo(First, Second, /*openArchetypes=*/true, *DC)) + case RequirementKind::Conformance: { + auto *M = DC->getParentModule(); + auto *Proto = Second->castTo()->getDecl(); + if (!First->isTypeParameter() && + !First->is() && + !M->conformsToProtocol(First, Proto)) return true; - else if (!isConvertibleTo(First, Second, /*openArchetypes=*/false, - *DC)) + if (!M->conformsToProtocol(First, Proto)) MergeInfo.addRequirement(GenericSig, First, Second, Kind); break; + } case RequirementKind::Superclass: if (!Second->isBindableToSuperclassOf(First)) { From 88a833f19c2027919699f0d72beda6700657c24f Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Fri, 20 Sep 2019 15:01:57 -0700 Subject: [PATCH 119/199] Reflection: Move resolveRelativeField functionality onto RemoteRef Resolving a direct relative reference given a RemoteRef doesn't need the MetadataReader, since the offset should already be in the local buffer; we can add it to RemoteRef's saved remote address and get a new remote address. Refactor the API to make as much as possible of it available directly on RemoteRef. --- include/swift/Reflection/TypeRefBuilder.h | 2 +- include/swift/Remote/MetadataReader.h | 125 +++++++++++----------- 2 files changed, 62 insertions(+), 65 deletions(-) diff --git a/include/swift/Reflection/TypeRefBuilder.h b/include/swift/Reflection/TypeRefBuilder.h index 7eb5838e802cd..701417a77c584 100644 --- a/include/swift/Reflection/TypeRefBuilder.h +++ b/include/swift/Reflection/TypeRefBuilder.h @@ -532,7 +532,7 @@ class TypeRefBuilder { if (context->getKind() == ContextDescriptorKind::OpaqueType) { return Dem.createNode( Node::Kind::OpaqueTypeDescriptorSymbolicReference, - (uintptr_t)context.template getAddress()); + context.getAddressData()); } return reader.buildContextMangling(context, Dem); diff --git a/include/swift/Remote/MetadataReader.h b/include/swift/Remote/MetadataReader.h index 8bbdb8b69059f..9db40a34aca64 100644 --- a/include/swift/Remote/MetadataReader.h +++ b/include/swift/Remote/MetadataReader.h @@ -62,11 +62,6 @@ class RemoteRef { return Address; } - template - typename Runtime::StoredPointer getAddress() const { - return (typename Runtime::StoredPointer)getAddressData(); - } - const T *getLocalBuffer() const { return LocalBuffer; } @@ -87,6 +82,26 @@ class RemoteRef { bool operator!=(RemoteRef other) const { return !operator==(other); } + + /// Project a reference for a field. The field must be projected from the same + /// LocalBuffer pointer as this RemoteRef. + template + RemoteRef getField(U &field) const { + auto offset = (intptr_t)&field - (intptr_t)LocalBuffer; + return RemoteRef((uint64_t)(Address + (int64_t)offset), &field); + } + + /// Resolve the remote address of a relative offset stored at the remote address. + uint64_t resolveRelativeAddressData() const { + int32_t offset; + memcpy(&offset, LocalBuffer, sizeof(int32_t)); + return Address + (int64_t)offset; + } + + template + uint64_t resolveRelativeFieldData(U &field) const { + return getField(field).resolveRelativeAddressData(); + } }; /// A structure, designed for use with std::unique_ptr, which destroys @@ -1077,14 +1092,13 @@ class MetadataReader { return ClassMetadataBounds::forSwiftRootClass(); auto rawSuperclass = - resolveNullableRelativeField(subclassRef, - subclass->getResilientSuperclass()); + resolveRelativeField(subclassRef, subclass->getResilientSuperclass()); if (!rawSuperclass) { return ClassMetadataBounds::forSwiftRootClass(); } return forTypeReference( - subclass->getResilientSuperclassReferenceKind(), *rawSuperclass, + subclass->getResilientSuperclassReferenceKind(), rawSuperclass, [&](ContextDescriptorRef superclass) -> Optional { if (!isa>(superclass)) @@ -1175,7 +1189,7 @@ class MetadataReader { return None; auto addressOfGenericArgAddress = - (Meta.template getAddress() + + (getAddress(Meta) + *offsetToGenericArgs * sizeof(StoredPointer) + index * sizeof(StoredPointer)); @@ -1246,31 +1260,6 @@ class MetadataReader { } protected: - template - StoredPointer resolveRelativeOffset(StoredPointer targetAddress) { - Offset relative; - if (!Reader->readInteger(RemoteAddress(targetAddress), &relative)) - return 0; - using SignedOffset = typename std::make_signed::type; - using SignedPointer = typename std::make_signed::type; - auto signext = (SignedPointer)(SignedOffset)relative; - return targetAddress + signext; - } - - template - Optional - resolveNullableRelativeOffset(StoredPointer targetAddress) { - Offset relative; - if (!Reader->readInteger(RemoteAddress(targetAddress), &relative)) - return None; - if (relative == 0) - return 0; - using SignedOffset = typename std::make_signed::type; - using SignedPointer = typename std::make_signed::type; - auto signext = (SignedPointer)(SignedOffset)relative; - return targetAddress + signext; - } - template Optional resolveNullableRelativeIndirectableOffset(StoredPointer targetAddress) { @@ -1299,33 +1288,44 @@ class MetadataReader { return resultAddress; } - template - StoredPointer resolveRelativeField( - RemoteRef base, const Field &field) { - // Map the offset from within our local buffer to the remote address. - auto distance = (intptr_t)&field - (intptr_t)base.getLocalBuffer(); - return resolveRelativeOffset( - base.template getAddress() + distance); + template + StoredPointer getAddress(RemoteRef base) { + return (StoredPointer)base.getAddressData(); } template - Optional resolveNullableRelativeField( + StoredPointer resolveRelativeField( RemoteRef base, const Field &field) { - // Map the offset from within our local buffer to the remote address. - auto distance = (intptr_t)&field - (intptr_t)base.getLocalBuffer(); - - return resolveNullableRelativeOffset( - base.template getAddress() + distance); + return (StoredPointer)base.resolveRelativeFieldData(field); } - + template - Optional resolveNullableRelativeIndirectableField( + Optional resolveRelativeIndirectableField( RemoteRef base, const Field &field) { - // Map the offset from within our local buffer to the remote address. - auto distance = (intptr_t)&field - (intptr_t)base.getLocalBuffer(); + auto fieldRef = base.getField(field); + int32_t offset; + memcpy(&offset, fieldRef.getLocalBuffer(), sizeof(int32_t)); + + if (offset == 0) + return 0; + bool indirect = offset & 1; + offset &= ~1u; - return resolveNullableRelativeIndirectableOffset( - base.template getAddress() + distance); + using SignedPointer = typename std::make_signed::type; + + StoredPointer resultAddress = getAddress(fieldRef) + (SignedPointer)offset; + + // Low bit set in the offset indicates that the offset leads to the absolute + // address in memory. + if (indirect) { + if (!Reader->readBytes(RemoteAddress(resultAddress), + (uint8_t *)&resultAddress, + sizeof(StoredPointer))) { + return None; + } + } + + return resultAddress; } /// Given a pointer to an Objective-C class, try to read its class name. @@ -1532,8 +1532,7 @@ class MetadataReader { /// Returns None if there was an error reading the parent descriptor. Optional readParentContextDescriptor(ContextDescriptorRef base) { - auto parentAddress = - resolveNullableRelativeIndirectableField(base, base->Parent); + auto parentAddress = resolveRelativeIndirectableField(base, base->Parent); if (!parentAddress) return None; if (!*parentAddress) @@ -1849,8 +1848,7 @@ class MetadataReader { const RelativeTargetProtocolDescriptorPointer &protocol) { // Map the offset from within our local buffer to the remote address. auto distance = (intptr_t)&protocol - (intptr_t)descriptor.getLocalBuffer(); - StoredPointer targetAddress( - descriptor.template getAddress() + distance); + StoredPointer targetAddress(getAddress(descriptor) + distance); // Read the relative offset. int32_t relative; @@ -2083,8 +2081,7 @@ class MetadataReader { // address. auto distance = (intptr_t)&req.Layout - (intptr_t)descriptor.getLocalBuffer(); - StoredPointer targetAddress( - descriptor.template getAddress() + distance); + StoredPointer targetAddress(getAddress(descriptor) + distance); GenericRequirementLayoutKind kind; if (!Reader->readBytes(RemoteAddress(targetAddress), @@ -2282,7 +2279,7 @@ class MetadataReader { if (!offsetToGenericArgs) return {}; - auto genericArgsAddr = metadata.template getAddress() + auto genericArgsAddr = getAddress(metadata) + sizeof(StoredPointer) * *offsetToGenericArgs; std::vector builtSubsts; @@ -2340,7 +2337,7 @@ class MetadataReader { // If we've skipped an artificial subclasses, check the cache at // the superclass. (This also protects against recursion.) if (skipArtificialSubclasses && metadata != origMetadata) { - auto it = TypeCache.find(metadata.template getAddress()); + auto it = TypeCache.find(getAddress(metadata)); if (it != TypeCache.end()) return it->second; } @@ -2370,12 +2367,12 @@ class MetadataReader { if (!nominal) return BuiltType(); - TypeCache[metadata.template getAddress()] = nominal; + TypeCache[getAddress(metadata)] = nominal; // If we've skipped an artificial subclass, remove the // recursion-protection entry we made for it. if (skipArtificialSubclasses && metadata != origMetadata) { - TypeCache.erase(origMetadata.template getAddress()); + TypeCache.erase(getAddress(origMetadata)); } return nominal; @@ -2388,7 +2385,7 @@ class MetadataReader { return readNominalTypeFromMetadata(origMetadata, skipArtificialSubclasses); std::string className; - auto origMetadataPtr = origMetadata.template getAddress(); + auto origMetadataPtr = getAddress(origMetadata); if (!readObjCClassName(origMetadataPtr, className)) return BuiltType(); From 0569cbfb28b0fee5976d85e517615c2288a73774 Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Fri, 20 Sep 2019 15:26:04 -0700 Subject: [PATCH 120/199] Revert "Revert "[SyntaxParse] Parse generic parameter clause and generic where clause"" This reverts commit 1584e87aa7dc92f1c4515da39367a63de1991e3a. --- cmake/modules/SwiftHandleGybSources.cmake | 2 + include/swift/Parse/ASTGen.h | 24 +- include/swift/Parse/Lexer.h | 4 +- .../swift/Parse/ParsedSyntaxBuilders.h.gyb | 2 +- include/swift/Parse/ParsedSyntaxNodes.h.gyb | 6 +- .../swift/Parse/ParsedSyntaxRecorder.h.gyb | 2 +- include/swift/Parse/Parser.h | 24 +- include/swift/Syntax/SyntaxBuilders.h.gyb | 2 +- include/swift/Syntax/SyntaxFactory.h.gyb | 2 +- include/swift/Syntax/SyntaxKind.h.gyb | 14 +- include/swift/Syntax/SyntaxNodes.h.gyb | 6 +- include/swift/Syntax/SyntaxVisitor.h.gyb | 2 +- lib/Parse/ASTGen.cpp | 195 +++++++- lib/Parse/ParseDecl.cpp | 1 + lib/Parse/ParseGeneric.cpp | 458 +++++++++--------- lib/Parse/ParseType.cpp | 114 ++--- lib/Parse/ParsedSyntaxBuilders.cpp.gyb | 2 +- lib/Parse/ParsedSyntaxNodes.cpp.gyb | 2 +- lib/Parse/ParsedSyntaxRecorder.cpp.gyb | 4 +- lib/Parse/Parser.cpp | 2 +- lib/ParseSIL/ParseSIL.cpp | 6 +- lib/Syntax/SyntaxBuilders.cpp.gyb | 2 +- lib/Syntax/SyntaxFactory.cpp.gyb | 10 +- lib/Syntax/SyntaxKind.cpp.gyb | 8 +- lib/Syntax/SyntaxNodes.cpp.gyb | 2 +- lib/Syntax/SyntaxVisitor.cpp.gyb | 4 +- test/Parse/invalid.swift | 2 +- .../round_trip_parse_gen.swift.withkinds | 22 +- unittests/Syntax/DeclSyntaxTests.cpp | 6 +- utils/gyb_syntax_support/GenericNodes.py | 55 ++- .../NodeSerializationCodes.py | 3 + utils/gyb_syntax_support/SILOnlyNodes.py | 9 + utils/gyb_syntax_support/__init__.py | 1 + 33 files changed, 634 insertions(+), 364 deletions(-) create mode 100644 utils/gyb_syntax_support/SILOnlyNodes.py diff --git a/cmake/modules/SwiftHandleGybSources.cmake b/cmake/modules/SwiftHandleGybSources.cmake index 1d37e4ae80958..7e858badf8e81 100644 --- a/cmake/modules/SwiftHandleGybSources.cmake +++ b/cmake/modules/SwiftHandleGybSources.cmake @@ -121,7 +121,9 @@ function(handle_gyb_sources dependency_out_var_name sources_var_name arch) "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/DeclNodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/ExprNodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/GenericNodes.py" + "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/NodeSerializationCodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/PatternNodes.py" + "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/SILOnlyNodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/StmtNodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/TypeNodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/Token.py" diff --git a/include/swift/Parse/ASTGen.h b/include/swift/Parse/ASTGen.h index 4f29a8bb3a8b0..591c8034548ea 100644 --- a/include/swift/Parse/ASTGen.h +++ b/include/swift/Parse/ASTGen.h @@ -22,21 +22,24 @@ namespace swift { /// Generates AST nodes from Syntax nodes. +class Parser; class ASTGen { ASTContext &Context; /// Type cache to prevent multiple transformations of the same syntax node. llvm::DenseMap TypeCache; - PersistentParserState **ParserState; + Parser &P; // FIXME: remove when Syntax can represent all types and ASTGen can handle them /// Types that cannot be represented by Syntax or generated by ASTGen. llvm::DenseMap Types; + llvm::DenseMap ParsedDeclAttrs; + public: - ASTGen(ASTContext &Context, PersistentParserState **ParserState) - : Context(Context), ParserState(ParserState) {} + ASTGen(ASTContext &Context, Parser &P) + : Context(Context), P(P) {} SourceLoc generate(syntax::TokenSyntax Tok, SourceLoc &Loc); @@ -70,6 +73,15 @@ class ASTGen { llvm::SmallVector generate(syntax::GenericArgumentListSyntax Args, SourceLoc &Loc); + GenericParamList * + generate(syntax::GenericParameterClauseListSyntax clause, SourceLoc &Loc); + GenericParamList * + generate(syntax::GenericParameterClauseSyntax clause, SourceLoc &Loc); + Optional + generate(syntax::GenericRequirementSyntax req, SourceLoc &Loc); + LayoutConstraint + generate(syntax::LayoutConstraintSyntax req, SourceLoc &Loc); + /// Copy a numeric literal value into AST-owned memory, stripping underscores /// so the semantic part of the value can be parsed by APInt/APFloat parsers. static StringRef copyAndStripUnderscores(StringRef Orig, ASTContext &Context); @@ -102,6 +114,8 @@ class ASTGen { ValueDecl *lookupInScope(DeclName Name); + void addToScope(ValueDecl *D, bool diagnoseRedefinitions = true); + TypeRepr *cacheType(syntax::TypeSyntax Type, TypeRepr *TypeAST); TypeRepr *lookupType(syntax::TypeSyntax Type); @@ -112,6 +126,10 @@ class ASTGen { bool hasType(const SourceLoc &Loc) const; TypeRepr *getType(const SourceLoc &Loc) const; + + void addDeclAttributes(DeclAttributes attrs, SourceLoc Loc); + bool hasDeclAttributes(SourceLoc Loc) const; + DeclAttributes getDeclAttributes(SourceLoc Loc) const; }; } // namespace swift diff --git a/include/swift/Parse/Lexer.h b/include/swift/Parse/Lexer.h index 8441a12dc17d4..2849c41f1eca3 100644 --- a/include/swift/Parse/Lexer.h +++ b/include/swift/Parse/Lexer.h @@ -200,8 +200,8 @@ class Lexer { ParsedTrivia &TrailingTriviaResult) { Result = NextToken; if (TriviaRetention == TriviaRetentionMode::WithTrivia) { - LeadingTriviaResult = {LeadingTrivia}; - TrailingTriviaResult = {TrailingTrivia}; + std::swap(LeadingTriviaResult, LeadingTrivia); + std::swap(TrailingTriviaResult, TrailingTrivia); } if (Result.isNot(tok::eof)) lexImpl(); diff --git a/include/swift/Parse/ParsedSyntaxBuilders.h.gyb b/include/swift/Parse/ParsedSyntaxBuilders.h.gyb index 90aba5e9eb212..0cfcf69bd32ce 100644 --- a/include/swift/Parse/ParsedSyntaxBuilders.h.gyb +++ b/include/swift/Parse/ParsedSyntaxBuilders.h.gyb @@ -30,7 +30,7 @@ namespace swift { class ParsedRawSyntaxRecorder; class SyntaxParsingContext; -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.is_buildable(): % child_count = len(node.children) class Parsed${node.name}Builder { diff --git a/include/swift/Parse/ParsedSyntaxNodes.h.gyb b/include/swift/Parse/ParsedSyntaxNodes.h.gyb index 5bbc07321f49d..8883b2ed796e8 100644 --- a/include/swift/Parse/ParsedSyntaxNodes.h.gyb +++ b/include/swift/Parse/ParsedSyntaxNodes.h.gyb @@ -28,20 +28,20 @@ namespace swift { % # Emit the non-collection classes first, then emit the collection classes % # that reference these classes. -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if not node.is_syntax_collection(): class Parsed${node.name}; % end % end -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.is_syntax_collection(): using Parsed${node.name} = ParsedSyntaxCollection; % end % end -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if not node.is_syntax_collection(): % qualifier = "" if node.is_base() else "final" % for line in dedented_lines(node.description): diff --git a/include/swift/Parse/ParsedSyntaxRecorder.h.gyb b/include/swift/Parse/ParsedSyntaxRecorder.h.gyb index 51b56c73aea07..5600ade0b5028 100644 --- a/include/swift/Parse/ParsedSyntaxRecorder.h.gyb +++ b/include/swift/Parse/ParsedSyntaxRecorder.h.gyb @@ -31,7 +31,7 @@ class SyntaxParsingContext; struct ParsedSyntaxRecorder { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.children: % child_params = [] % for child in node.children: diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 9ccac31e34256..91ee72590704c 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -695,11 +695,19 @@ class Parser { /// plain Tok.is(T1) check). bool skipUntilTokenOrEndOfLine(tok T1); + //-------------------------------------------------------------------------// + // Ignore token APIs. + // This is used when we skip gabage text in the source text. + + /// Ignore the current single token. void ignoreToken(); void ignoreToken(tok Kind) { + /// Ignore the current single token asserting its kind. assert(Tok.is(Kind)); ignoreToken(); } + /// Conditionally ignore the current single token if it matches with the \p + /// Kind. bool ignoreIf(tok Kind) { if (!Tok.is(Kind)) return false; @@ -1173,7 +1181,8 @@ class Parser { using TypeASTResult = ParserResult; using TypeResult = ParsedSyntaxResult; - LayoutConstraint parseLayoutConstraint(Identifier LayoutConstraintID); + ParsedSyntaxResult + parseLayoutConstraintSyntax(); TypeResult parseTypeSyntax(); TypeResult parseTypeSyntax(Diag<> MessageID, bool HandleCodeCompletion = true, @@ -1597,8 +1606,19 @@ class Parser { //===--------------------------------------------------------------------===// // Generics Parsing + ParserResult parseSILGenericParams(); + + ParserStatus parseSILGenericParamsSyntax( + Optional &result); + + ParsedSyntaxResult + parseGenericParameterClauseSyntax(); + + ParsedSyntaxResult + parseGenericWhereClauseSyntax(bool &FirstTypeInComplete, + bool AllowLayoutConstraints = false); + ParserResult parseGenericParameters(); - ParserResult parseGenericParameters(SourceLoc LAngleLoc); ParserStatus parseGenericParametersBeforeWhere(SourceLoc LAngleLoc, SmallVectorImpl &GenericParams); ParserResult maybeParseGenericParams(); diff --git a/include/swift/Syntax/SyntaxBuilders.h.gyb b/include/swift/Syntax/SyntaxBuilders.h.gyb index 7fe71ed159a3d..177d6779fe45e 100644 --- a/include/swift/Syntax/SyntaxBuilders.h.gyb +++ b/include/swift/Syntax/SyntaxBuilders.h.gyb @@ -29,7 +29,7 @@ namespace syntax { class SyntaxArena; -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.is_buildable(): % child_count = len(node.children) class ${node.name}Builder { diff --git a/include/swift/Syntax/SyntaxFactory.h.gyb b/include/swift/Syntax/SyntaxFactory.h.gyb index 387279d73f891..be88f173d5697 100644 --- a/include/swift/Syntax/SyntaxFactory.h.gyb +++ b/include/swift/Syntax/SyntaxFactory.h.gyb @@ -71,7 +71,7 @@ struct SyntaxFactory { static Syntax makeBlankCollectionSyntax(SyntaxKind Kind); -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.children: % child_params = [] % for child in node.children: diff --git a/include/swift/Syntax/SyntaxKind.h.gyb b/include/swift/Syntax/SyntaxKind.h.gyb index 21f344a572352..10291bad736b7 100644 --- a/include/swift/Syntax/SyntaxKind.h.gyb +++ b/include/swift/Syntax/SyntaxKind.h.gyb @@ -2,7 +2,7 @@ from gyb_syntax_support import * from gyb_syntax_support.kinds import SYNTAX_BASE_KINDS grouped_nodes = { kind: [] for kind in SYNTAX_BASE_KINDS } - for node in SYNTAX_NODES: + for node in SYNTAX_NODES + SILONLY_NODES: grouped_nodes[node.base_kind].append(node) # -*- mode: C++ -*- # Ignore the following admonition; it applies to the resulting .h file only @@ -89,12 +89,14 @@ struct WrapperTypeTraits { return 0; case syntax::SyntaxKind::Unknown: return 1; -% for name, nodes in grouped_nodes.items(): -% for node in nodes: +% for node in SYNTAX_NODES: case syntax::SyntaxKind::${node.syntax_kind}: return ${SYNTAX_NODE_SERIALIZATION_CODES[node.syntax_kind]}; -% end % end +% for node in SILONLY_NODES: + case syntax::SyntaxKind::${node.syntax_kind}: +% end + llvm_unreachable("unserializable syntax kind"); } llvm_unreachable("unhandled kind"); } @@ -122,6 +124,10 @@ struct ScalarReferenceTraits { case syntax::SyntaxKind::${node.syntax_kind}: return "\"${node.syntax_kind}\""; % end +% for node in SILONLY_NODES: + case syntax::SyntaxKind::${node.syntax_kind}: +% end + llvm_unreachable("unserializable syntax kind"); } llvm_unreachable("unhandled kind"); } diff --git a/include/swift/Syntax/SyntaxNodes.h.gyb b/include/swift/Syntax/SyntaxNodes.h.gyb index 65219ce8489d1..0e4a9a9bf5d54 100644 --- a/include/swift/Syntax/SyntaxNodes.h.gyb +++ b/include/swift/Syntax/SyntaxNodes.h.gyb @@ -32,13 +32,13 @@ namespace syntax { % # Emit the non-collection classes first, then emit the collection classes % # that reference these classes. -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if not node.is_syntax_collection(): class ${node.name}; % end % end -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.is_syntax_collection(): using ${node.name} = SyntaxCollection()) TypeAST = generate(*SimpleIdentifier, Loc); @@ -224,7 +223,7 @@ TypeRepr *ASTGen::generate(AttributedTypeSyntax Type, SourceLoc &Loc) { if (AttrKind == TAK_convention) { auto Argument = Attr.getArgument()->castTo(); - auto Convention = Context.getIdentifier(Argument.getText()); + auto Convention = Context.getIdentifier(Argument.getIdentifierText()); TypeAttrs.convention = Convention.str(); } @@ -339,9 +338,10 @@ TypeRepr *ASTGen::generateSimpleOrMemberIdentifier(T Type, SourceLoc &Loc) { auto FirstComponent = IdentType->getComponentRange().front(); // Lookup element #0 through our current scope chains in case it is some // thing local (this returns null if nothing is found). - if (auto Entry = lookupInScope(FirstComponent->getIdentifier())) + if (auto Entry = lookupInScope(FirstComponent->getIdentifier())) { if (auto *TD = dyn_cast(Entry)) FirstComponent->setValue(TD, nullptr); + } return IdentType; } @@ -369,6 +369,11 @@ TypeRepr *ASTGen::generate(SimpleTypeIdentifierSyntax Type, SourceLoc &Loc) { auto AnyLoc = advanceLocBegin(Loc, Type.getName()); return CompositionTypeRepr::createEmptyComposition(Context, AnyLoc); } + if (Type.getName().getText() == "class") { + auto classLoc = advanceLocBegin(Loc, Type.getName()); + return new (Context) SimpleIdentTypeRepr(classLoc, + Context.getIdentifier("AnyObject")); + } return generateSimpleOrMemberIdentifier(Type, Loc); } @@ -512,6 +517,162 @@ StringRef ASTGen::copyAndStripUnderscores(StringRef Orig, ASTContext &Context) { return StringRef(start, p - start); } +GenericParamList *ASTGen::generate(GenericParameterClauseListSyntax clauses, + SourceLoc &Loc) { + GenericParamList *curr = nullptr; + + // The first one is the outmost generic parameter list. + for (const auto &clause : clauses) { + auto params = generate(clause, Loc); + if (!params) + continue; + params->setOuterParameters(curr); + curr = params; + } + + return curr; +} + +GenericParamList *ASTGen::generate(GenericParameterClauseSyntax clause, + SourceLoc &Loc) { + SmallVector params; + params.reserve(clause.getGenericParameterList().getNumChildren()); + + for (auto elem : clause.getGenericParameterList()) { + + DeclAttributes attrs; + if (auto attrsSyntax = elem.getAttributes()) { + auto attrsLoc = advanceLocBegin(Loc, *attrsSyntax->getFirstToken()); + attrs = getDeclAttributes(attrsLoc); + } + Identifier name = Context.getIdentifier(elem.getName().getIdentifierText()); + SourceLoc nameLoc = advanceLocBegin(Loc, elem.getName()); + + // We always create generic type parameters with an invalid depth. + // Semantic analysis fills in the depth when it processes the generic + // parameter list. + auto param = new (Context) + GenericTypeParamDecl(P.CurDeclContext, name, nameLoc, + GenericTypeParamDecl::InvalidDepth, params.size()); + + if (auto inherited = elem.getInheritedType()) { + if (auto ty = generate(*inherited, Loc)) { + SmallVector constraints = {generate(*inherited, Loc)}; + param->setInherited(Context.AllocateCopy(constraints)); + } + } + + // Attach attributes. + param->getAttrs() = attrs; + + // Add this parameter to the scope. + addToScope(param); + + params.push_back(param); + } + if (params.empty()) + return nullptr; + + SourceLoc whereLoc; + SmallVector requirements; + if (auto whereClause = clause.getObsoletedWhereClause()) { + requirements.reserve(whereClause->getRequirementList().size()); + for (auto elem : whereClause->getRequirementList()) { + if (auto req = generate(elem, Loc)) + requirements.push_back(*req); + } + // There's an invariant that valid 'where' loc means that there's at + // at least one valid requirement. + if (!requirements.empty()) + whereLoc = advanceLocBegin(Loc, whereClause->getWhereKeyword()); + } + + auto lAngleLoc = advanceLocBegin(Loc, clause.getLeftAngleBracket()); + auto rAngleLoc = advanceLocBegin(Loc, clause.getRightAngleBracket()); + return GenericParamList::create(Context, lAngleLoc, params, whereLoc, + requirements, rAngleLoc); +} + +Optional ASTGen::generate(syntax::GenericRequirementSyntax req, + SourceLoc &Loc) { + if (auto sameTypeReq = req.getBody().getAs()) { + auto firstType = generate(sameTypeReq->getLeftTypeIdentifier(), Loc); + auto secondType = generate(sameTypeReq->getRightTypeIdentifier(), Loc); + if (!firstType || !secondType) + return None; + return RequirementRepr::getSameType( + firstType, advanceLocBegin(Loc, sameTypeReq->getEqualityToken()), + secondType); + } else if (auto conformanceReq = + req.getBody().getAs()) { + auto firstType = generate(conformanceReq->getLeftTypeIdentifier(), Loc); + auto secondType = generate(conformanceReq->getRightTypeIdentifier(), Loc); + if (!firstType || !secondType) + return None; + return RequirementRepr::getTypeConstraint( + firstType, advanceLocBegin(Loc, conformanceReq->getColon()), + secondType); + } else if (auto layoutReq = req.getBody().getAs()) { + auto firstType = generate(layoutReq->getLeftTypeIdentifier(), Loc); + auto layout = generate(layoutReq->getLayoutConstraint(), Loc); + if (!firstType || layout.isNull()) + return None; + auto colonLoc = advanceLocBegin(Loc, layoutReq->getColon()); + auto layoutLoc = advanceLocBegin(Loc, layoutReq->getLayoutConstraint()); + return RequirementRepr::getLayoutConstraint( + firstType, colonLoc, LayoutConstraintLoc(layout, layoutLoc)); + } else { + llvm_unreachable("invalid syntax kind for requirement body"); + } +} + +static LayoutConstraintKind getLayoutConstraintKind(Identifier &id, + ASTContext &Ctx) { + if (id == Ctx.Id_TrivialLayout) + return LayoutConstraintKind::TrivialOfExactSize; + if (id == Ctx.Id_TrivialAtMostLayout) + return LayoutConstraintKind::TrivialOfAtMostSize; + if (id == Ctx.Id_RefCountedObjectLayout) + return LayoutConstraintKind::RefCountedObject; + if (id == Ctx.Id_NativeRefCountedObjectLayout) + return LayoutConstraintKind::NativeRefCountedObject; + if (id == Ctx.Id_ClassLayout) + return LayoutConstraintKind::Class; + if (id == Ctx.Id_NativeClassLayout) + return LayoutConstraintKind::NativeClass; + return LayoutConstraintKind::UnknownLayout; +} + +LayoutConstraint ASTGen::generate(LayoutConstraintSyntax constraint, + SourceLoc &Loc) { + auto name = Context.getIdentifier(constraint.getName().getIdentifierText()); + auto constraintKind = getLayoutConstraintKind(name, Context); + assert(constraintKind != LayoutConstraintKind::UnknownLayout); + + // Non-trivial constraint kinds don't have size/alignment. + // TODO: Diagnose if it's supplied? + if (!LayoutConstraintInfo::isTrivial(constraintKind)) + return LayoutConstraint::getLayoutConstraint(constraintKind, Context); + + // '_Trivial' without explicit size/alignment. + if (!constraint.getSize()) + return LayoutConstraint::getLayoutConstraint(LayoutConstraintKind::Trivial, + Context); + + int size = 0; + if (auto sizeSyntax = constraint.getSize()) + sizeSyntax->getText().getAsInteger(10, size); + assert(size >= 0); + + int alignment = 0; + if (auto alignmentSyntax = constraint.getAlignment()) + alignmentSyntax->getText().getAsInteger(10, alignment); + assert(alignment >= 0); + + return LayoutConstraint::getLayoutConstraint(constraintKind, size, alignment, + Context); +} + SourceLoc ASTGen::advanceLocBegin(const SourceLoc &Loc, const Syntax &Node) { return Loc.getAdvancedLoc(Node.getAbsolutePosition().getOffset()); } @@ -550,9 +711,11 @@ MagicIdentifierLiteralExpr::Kind ASTGen::getMagicIdentifierLiteralKind(tok Kind) } ValueDecl *ASTGen::lookupInScope(DeclName Name) { - return Context.LangOpts.EnableASTScopeLookup && Context.LangOpts.DisableParserLookup - ? nullptr - : (*ParserState)->getScopeInfo().lookupValueName(Name); + return P.lookupInScope(Name); +} + +void ASTGen::addToScope(ValueDecl *D, bool diagnoseRedefinitions) { + P.addToScope(D, diagnoseRedefinitions); } TypeRepr *ASTGen::cacheType(TypeSyntax Type, TypeRepr *TypeAST) { @@ -576,3 +739,15 @@ bool ASTGen::hasType(const SourceLoc &Loc) const { TypeRepr *ASTGen::getType(const SourceLoc &Loc) const { return Types.find(Loc)->second; } + +void ASTGen::addDeclAttributes(DeclAttributes attrs, SourceLoc Loc) { + ParsedDeclAttrs.insert({Loc, attrs}); +} + +bool ASTGen::hasDeclAttributes(SourceLoc Loc) const { + return ParsedDeclAttrs.find(Loc) != ParsedDeclAttrs.end(); +} + +DeclAttributes ASTGen::getDeclAttributes(SourceLoc Loc) const { + return ParsedDeclAttrs.find(Loc)->second; +} diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 8400738a7a5b5..aac270c73ddae 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -16,6 +16,7 @@ #include "swift/Parse/Parser.h" #include "swift/Parse/CodeCompletionCallbacks.h" +#include "swift/Parse/ParsedSyntaxBuilders.h" #include "swift/Parse/ParsedSyntaxRecorder.h" #include "swift/Parse/ParseSILSupport.h" #include "swift/Parse/SyntaxParsingContext.h" diff --git a/lib/Parse/ParseGeneric.cpp b/lib/Parse/ParseGeneric.cpp index 912784c0ad044..ee00e32c6aad8 100644 --- a/lib/Parse/ParseGeneric.cpp +++ b/lib/Parse/ParseGeneric.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,185 +10,185 @@ // //===----------------------------------------------------------------------===// // -// Generic Parsing and AST Building +// Generic Parsing // //===----------------------------------------------------------------------===// #include "swift/Parse/Parser.h" #include "swift/AST/DiagnosticsParse.h" -#include "swift/Parse/CodeCompletionCallbacks.h" +#include "swift/Parse/ParsedSyntaxBuilders.h" +#include "swift/Parse/ParsedSyntaxRecorder.h" #include "swift/Parse/SyntaxParsingContext.h" -#include "swift/Parse/Lexer.h" -#include "swift/Syntax/SyntaxBuilders.h" -#include "swift/Syntax/SyntaxNodes.h" + using namespace swift; using namespace swift::syntax; -/// parseGenericParameters - Parse a sequence of generic parameters, e.g., -/// < T : Comparable, U : Container> along with an optional requires clause. +/// Parse a list of generic parameters. +/// +/// generic-parameter-clause-list: +/// generic-parameter-clause generic-parameter-clause* +ParserStatus Parser::parseSILGenericParamsSyntax( + Optional &result) { + assert(isInSILMode()); + ParserStatus status; + if (!startsWithLess(Tok)) + return status; + + SmallVector clauses; + do { + auto result = parseGenericParameterClauseSyntax(); + status |= result.getStatus(); + if (!result.isNull()) + clauses.push_back(result.get()); + } while (startsWithLess(Tok)); + + result = ParsedSyntaxRecorder::makeGenericParameterClauseList(clauses, + *SyntaxContext); + return status; +} + +/// Parse a sequence of generic parameters, e.g. '' +/// along with an optional requires clause. /// -/// generic-params: -/// '<' generic-param (',' generic-param)* where-clause? '>' +/// generic-parameter-clause: +/// '<' generic-paramter (',' generic-parameter)* where-clause? '>' /// -/// generic-param: +/// generic-parameter: /// identifier -/// identifier ':' type-identifier -/// identifier ':' type-composition -/// -/// When parsing the generic parameters, this routine establishes a new scope -/// and adds those parameters to the scope. -ParserResult Parser::parseGenericParameters() { - SyntaxParsingContext GPSContext(SyntaxContext, SyntaxKind::GenericParameterClause); - // Parse the opening '<'. +/// identifier ':' type +ParsedSyntaxResult +Parser::parseGenericParameterClauseSyntax() { assert(startsWithLess(Tok) && "Generic parameter list must start with '<'"); - return parseGenericParameters(consumeStartingLess()); -} + ParsedGenericParameterClauseSyntaxBuilder builder(*SyntaxContext); + ParserStatus status; -ParserStatus -Parser::parseGenericParametersBeforeWhere(SourceLoc LAngleLoc, - SmallVectorImpl &GenericParams) { - ParserStatus Result; - SyntaxParsingContext GPSContext(SyntaxContext, SyntaxKind::GenericParameterList); - bool HasNextParam; + // Parse '<'. + SourceLoc LAngleLoc = Tok.getLoc(); + builder.useLeftAngleBracket(consumeStartingLessSyntax()); + + // Parse parameters. + bool hasNext = true; do { - SyntaxParsingContext GParamContext(SyntaxContext, SyntaxKind::GenericParameter); - // Note that we're parsing a declaration. - StructureMarkerRAII ParsingDecl(*this, Tok.getLoc(), - StructureMarkerKind::Declaration); - - if (ParsingDecl.isFailed()) { - return makeParserError(); - } + ParsedGenericParameterSyntaxBuilder paramBuilder(*SyntaxContext); // Parse attributes. - DeclAttributes attributes; - if (Tok.hasComment()) - attributes.add(new (Context) RawDocCommentAttr(Tok.getCommentRange())); - parseDeclAttributeList(attributes); + // TODO: Implement syntax attribute parsing. + DeclAttributes attrsAST; + parseDeclAttributeList(attrsAST); + auto attrs = SyntaxContext->popIf(); + if (attrs) { + paramBuilder.useAttributes(std::move(*attrs)); + Generator.addDeclAttributes(attrsAST, attrsAST.getStartLoc()); + } // Parse the name of the parameter. - Identifier Name; - SourceLoc NameLoc; - if (parseIdentifier(Name, NameLoc, - diag::expected_generics_parameter_name)) { - Result.setIsParseError(); + auto ident = Context.getIdentifier(Tok.getText()); + auto name = parseIdentifierSyntax(diag::expected_generics_parameter_name); + if (!name) { + status.setIsParseError(); break; } + paramBuilder.useName(std::move(*name)); // Parse the ':' followed by a type. - SmallVector Inherited; if (Tok.is(tok::colon)) { - (void)consumeToken(); - ParserResult Ty; - + paramBuilder.useColon(consumeTokenSyntax(tok::colon)); if (Tok.isAny(tok::identifier, tok::code_complete, tok::kw_protocol, tok::kw_Any)) { - Ty = parseType(); - } else if (Tok.is(tok::kw_class)) { - diagnose(Tok, diag::unexpected_class_constraint); - diagnose(Tok, diag::suggest_anyobject) - .fixItReplace(Tok.getLoc(), "AnyObject"); - consumeToken(); - Result.setIsParseError(); + auto tyResult = parseTypeSyntax(); + status |= tyResult.getStatus(); + if (auto ty = tyResult.getOrNull()) + paramBuilder.useInheritedType(std::move(*ty)); } else { - diagnose(Tok, diag::expected_generics_type_restriction, Name); - Result.setIsParseError(); - } - - if (Ty.hasCodeCompletion()) - return makeParserCodeCompletionStatus(); + if (Tok.is(tok::kw_class)) { + diagnose(Tok, diag::unexpected_class_constraint); + diagnose(Tok, diag::suggest_anyobject) + .fixItReplace(Tok.getLoc(), "AnyObject"); + Tok.setKind(tok::identifier); + auto ty = ParsedSyntaxRecorder::makeSimpleTypeIdentifier( + consumeTokenSyntax(), None, *SyntaxContext); + paramBuilder.useInheritedType(std::move(ty)); + } else { + diagnose(Tok, diag::expected_generics_type_restriction, ident); - if (Ty.isNonNull()) - Inherited.push_back(Ty.get()); + paramBuilder.useInheritedType( + ParsedSyntaxRecorder::makeUnknownType({}, *SyntaxContext)); + } + status.setIsParseError(); + } } - // We always create generic type parameters with an invalid depth. - // Semantic analysis fills in the depth when it processes the generic - // parameter list. - auto Param = new (Context) GenericTypeParamDecl(CurDeclContext, Name, NameLoc, - GenericTypeParamDecl::InvalidDepth, - GenericParams.size()); - if (!Inherited.empty()) - Param->setInherited(Context.AllocateCopy(Inherited)); - GenericParams.push_back(Param); - - // Attach attributes. - Param->getAttrs() = attributes; - - // Add this parameter to the scope. - addToScope(Param); - - // Parse the comma, if the list continues. - HasNextParam = consumeIf(tok::comma); - } while (HasNextParam); + // Parse ',' + hasNext = Tok.is(tok::comma); + if (hasNext) + paramBuilder.useTrailingComma(consumeTokenSyntax(tok::comma)); - return Result; -} - -ParserResult -Parser::parseGenericParameters(SourceLoc LAngleLoc) { - // Parse the generic parameter list. - SmallVector GenericParams; - auto Result = parseGenericParametersBeforeWhere(LAngleLoc, GenericParams); + builder.addGenericParameterListMember(paramBuilder.build()); + } while (hasNext); - // Return early if there was code completion token. - if (Result.hasCodeCompletion()) - return Result; - auto Invalid = Result.isError(); - - // Parse the optional where-clause. - SourceLoc WhereLoc; - SmallVector Requirements; - bool FirstTypeInComplete; - if (Tok.is(tok::kw_where) && - parseGenericWhereClause(WhereLoc, Requirements, - FirstTypeInComplete).isError()) { - Invalid = true; + // Parse optional where clause. + SourceLoc whereLoc; + if (Tok.is(tok::kw_where)) { + SmallVector requirementAST; + bool FirstTypeInComplete = false; + auto where = parseGenericWhereClauseSyntax(FirstTypeInComplete); + builder.useObsoletedWhereClause(where.get()); } - + // Parse the closing '>'. - SourceLoc RAngleLoc; if (startsWithGreater(Tok)) { - RAngleLoc = consumeStartingGreater(); + builder.useRightAngleBracket(consumeStartingGreaterSyntax()); } else { - if (!Invalid) { + if (!status.isError()) { diagnose(Tok, diag::expected_rangle_generics_param); diagnose(LAngleLoc, diag::opening_angle); - Invalid = true; } // Skip until we hit the '>'. - RAngleLoc = skipUntilGreaterInTypeList(); + if (ignoreUntilGreaterInTypeList()) + builder.useRightAngleBracket(consumeStartingGreaterSyntax()); + status.setIsParseError(); } - if (GenericParams.empty()) - return nullptr; + return makeParsedResult(builder.build(), status); +} - return makeParserResult(GenericParamList::create(Context, LAngleLoc, - GenericParams, WhereLoc, - Requirements, RAngleLoc)); +ParserResult Parser::parseGenericParameters() { + auto loc = leadingTriviaLoc(); + auto syntaxResult = parseGenericParameterClauseSyntax(); + if (syntaxResult.isNull()) + return syntaxResult.getStatus(); + SyntaxContext->addSyntax(syntaxResult.get()); + + auto clause = SyntaxContext->topNode(); + if (clause.getGenericParameterList().empty()) + return nullptr; + return makeParserResult(syntaxResult.getStatus(), + Generator.generate(clause, loc)); } ParserResult Parser::maybeParseGenericParams() { if (!startsWithLess(Tok)) return nullptr; + return parseGenericParameters(); +} - if (!isInSILMode()) - return parseGenericParameters(); - - // In SIL mode, we can have multiple generic parameter lists, with the - // first one being the outmost generic parameter list. - GenericParamList *gpl = nullptr, *outer_gpl = nullptr; - do { - gpl = parseGenericParameters().getPtrOrNull(); - if (!gpl) - return nullptr; +ParserResult Parser::parseSILGenericParams() { + assert(isInSILMode()); + auto loc = leadingTriviaLoc(); + Optional result; + auto status = parseSILGenericParamsSyntax(result); + if (!result.hasValue()) { + status.setIsParseError(); + return status; + } - if (outer_gpl) - gpl->setOuterParameters(outer_gpl); - outer_gpl = gpl; - } while (startsWithLess(Tok)); - return makeParserResult(gpl); + SyntaxContext->addSyntax(std::move(*result)); + auto list = SyntaxContext->topNode(); + auto ret = Generator.generate(list, loc); + if (!ret) + return nullptr; + return makeParserResult(status, ret); } void @@ -242,131 +242,145 @@ Parser::diagnoseWhereClauseInGenericParamList(const GenericParamList * } } -/// parseGenericWhereClause - Parse a 'where' clause, which places additional -/// constraints on generic parameters or types based on them. +/// Parse a 'where' clause, which places additional constraints on generic +/// parameters or types based on them. /// /// where-clause: -/// 'where' requirement (',' requirement) * +/// 'where' generic-requirement (',' generic-requirement) * /// -/// requirement: +/// generic-requirement: /// conformance-requirement /// same-type-requirement +/// layout-requirement /// /// conformance-requirement: -/// type-identifier ':' type-identifier -/// type-identifier ':' type-composition +/// type ':' type /// /// same-type-requirement: -/// type-identifier '==' type -ParserStatus Parser::parseGenericWhereClause( - SourceLoc &WhereLoc, - SmallVectorImpl &Requirements, - bool &FirstTypeInComplete, - bool AllowLayoutConstraints) { - SyntaxParsingContext ClauseContext(SyntaxContext, - SyntaxKind::GenericWhereClause); - ParserStatus Status; - // Parse the 'where'. - WhereLoc = consumeToken(tok::kw_where); - FirstTypeInComplete = false; - SyntaxParsingContext ReqListContext(SyntaxContext, - SyntaxKind::GenericRequirementList); - bool HasNextReq; +/// type '==' type +/// +/// layout-requirement: +/// type ':' layout-constraint +ParsedSyntaxResult +Parser::parseGenericWhereClauseSyntax(bool &FirstTypeInComplete, + bool allowLayoutConstraints) { + ParsedGenericWhereClauseSyntaxBuilder builder(*SyntaxContext); + ParserStatus status; + + // Parse 'where'. + builder.useWhereKeyword(consumeTokenSyntax(tok::kw_where)); + + bool hasNext = true; do { - SyntaxParsingContext ReqContext(SyntaxContext, SyntaxContextKind::Syntax); - // Parse the leading type. It doesn't necessarily have to be just a type - // identifier if we're dealing with a same-type constraint. - ParserResult FirstType = parseType(); - - if (FirstType.hasCodeCompletion()) { - Status.setHasCodeCompletion(); - FirstTypeInComplete = true; - } - - if (FirstType.isNull()) { - Status.setIsParseError(); + auto firstType = parseTypeSyntax(); + status |= firstType.getStatus(); + FirstTypeInComplete = firstType.hasCodeCompletion(); + if (firstType.isNull()) break; - } + + ParsedGenericRequirementSyntaxBuilder elementBuilder(*SyntaxContext); if (Tok.is(tok::colon)) { - // A conformance-requirement. - SourceLoc ColonLoc = consumeToken(); - ReqContext.setCreateSyntax(SyntaxKind::ConformanceRequirement); + auto colon = consumeTokenSyntax(tok::colon); + if (Tok.is(tok::identifier) && getLayoutConstraint(Context.getIdentifier(Tok.getText()), Context) ->isKnownLayout()) { - // Parse a layout constraint. - Identifier LayoutName; - auto LayoutLoc = consumeIdentifier(&LayoutName); - auto LayoutInfo = parseLayoutConstraint(LayoutName); - if (!LayoutInfo->isKnownLayout()) { - // There was a bug in the layout constraint. - Status.setIsParseError(); - } - auto Layout = LayoutInfo; - // Types in SIL mode may contain layout constraints. - if (!AllowLayoutConstraints && !isInSILMode()) { - diagnose(LayoutLoc, + // Layout constraint. + ParsedLayoutRequirementSyntaxBuilder layoutReqBuilder(*SyntaxContext); + layoutReqBuilder.useLeftTypeIdentifier(firstType.get()); + layoutReqBuilder.useColon(std::move(colon)); + SourceLoc layoutLoc = Tok.getLoc(); + auto layout = parseLayoutConstraintSyntax(); + status |= layout.getStatus(); + + if (!allowLayoutConstraints && !isInSILMode()) + diagnose(layoutLoc, diag::layout_constraints_only_inside_specialize_attr); - } else { - // Add the layout requirement. - Requirements.push_back(RequirementRepr::getLayoutConstraint( - FirstType.get(), ColonLoc, - LayoutConstraintLoc(Layout, LayoutLoc))); - } + assert(!layout.isNull()); + layoutReqBuilder.useLayoutConstraint(layout.get()); + elementBuilder.useBody(layoutReqBuilder.build()); } else { - // Parse the protocol or composition. - ParserResult Protocol = parseType(); - - if (Protocol.isNull()) { - Status.setIsParseError(); - if (Protocol.hasCodeCompletion()) - Status.setHasCodeCompletion(); - break; - } - - // Add the requirement. - Requirements.push_back(RequirementRepr::getTypeConstraint( - FirstType.get(), ColonLoc, Protocol.get())); + // Conformance requirement. + ParsedConformanceRequirementSyntaxBuilder conformanceReqBuilder( + *SyntaxContext); + conformanceReqBuilder.useLeftTypeIdentifier(firstType.get()); + conformanceReqBuilder.useColon(std::move(colon)); + auto secondType = parseTypeSyntax(); + status |= secondType.getStatus(); + if (!secondType.isNull()) + conformanceReqBuilder.useRightTypeIdentifier(secondType.get()); + else + conformanceReqBuilder.useRightTypeIdentifier( + ParsedSyntaxRecorder::makeUnknownType({}, *SyntaxContext)); + elementBuilder.useBody(conformanceReqBuilder.build()); } } else if ((Tok.isAnyOperator() && Tok.getText() == "==") || Tok.is(tok::equal)) { - ReqContext.setCreateSyntax(SyntaxKind::SameTypeRequirement); - // A same-type-requirement + // Same type requirement. + ParsedSameTypeRequirementSyntaxBuilder sametypeReqBuilder(*SyntaxContext); + sametypeReqBuilder.useLeftTypeIdentifier(firstType.get()); if (Tok.is(tok::equal)) { diagnose(Tok, diag::requires_single_equal) - .fixItReplace(SourceRange(Tok.getLoc()), "=="); - } - SourceLoc EqualLoc = consumeToken(); - - // Parse the second type. - ParserResult SecondType = parseType(); - if (SecondType.isNull()) { - Status.setIsParseError(); - if (SecondType.hasCodeCompletion()) - Status.setHasCodeCompletion(); - break; + .fixItReplace(SourceRange(Tok.getLoc()), "=="); + ignoreToken(); + } else { + sametypeReqBuilder.useEqualityToken(consumeTokenSyntax()); } - // Add the requirement - Requirements.push_back(RequirementRepr::getSameType(FirstType.get(), - EqualLoc, - SecondType.get())); + auto secondType = parseTypeSyntax(); + status |= secondType.getStatus(); + if (!secondType.isNull()) + sametypeReqBuilder.useRightTypeIdentifier(secondType.get()); + else + sametypeReqBuilder.useRightTypeIdentifier( + ParsedSyntaxRecorder::makeUnknownType({}, *SyntaxContext)); + elementBuilder.useBody(sametypeReqBuilder.build()); } else { diagnose(Tok, diag::expected_requirement_delim); - Status.setIsParseError(); - break; + status.setIsParseError(); + + // Fallback to conformance requirement with missing right type. + ParsedConformanceRequirementSyntaxBuilder conformanceReqBuilder( + *SyntaxContext); + conformanceReqBuilder.useLeftTypeIdentifier(firstType.get()); + conformanceReqBuilder.useRightTypeIdentifier( + ParsedSyntaxRecorder::makeUnknownType({}, *SyntaxContext)); + elementBuilder.useBody(conformanceReqBuilder.build()); } - HasNextReq = consumeIf(tok::comma); - // If there's a comma, keep parsing the list. - } while (HasNextReq); - if (Requirements.empty()) - WhereLoc = SourceLoc(); + // Parse ','. + hasNext = (status.isSuccess() && Tok.is(tok::comma)); + if (hasNext) + elementBuilder.useTrailingComma(consumeTokenSyntax()); + + builder.addRequirementListMember(elementBuilder.build()); + } while (hasNext && status.isSuccess()); - return Status; + return makeParsedResult(builder.build(), status); } +ParserStatus Parser::parseGenericWhereClause( + SourceLoc &whereLoc, SmallVectorImpl &requirements, + bool &FirstTypeInComplete, bool AllowLayoutConstraints) { + auto loc = leadingTriviaLoc(); + auto syntaxResult = parseGenericWhereClauseSyntax(FirstTypeInComplete, + AllowLayoutConstraints); + if (syntaxResult.isNull()) + return syntaxResult.getStatus(); + + SyntaxContext->addSyntax(syntaxResult.get()); + auto clause = SyntaxContext->topNode(); + + whereLoc = Generator.generate(clause.getWhereKeyword(), loc); + requirements.reserve(clause.getRequirementList().size()); + for (auto elem : clause.getRequirementList()) { + if (auto req = Generator.generate(elem, loc)) + requirements.push_back(*req); + } + + return syntaxResult.getStatus(); +} /// Parse a free-standing where clause attached to a declaration, adding it to /// a generic parameter list that may (or may not) already exist. diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 7b4eaf46862a9..f6542b3da80b1 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -61,81 +61,61 @@ TypeRepr *Parser::applyAttributeToType(TypeRepr *ty, return ty; } -LayoutConstraint Parser::parseLayoutConstraint(Identifier LayoutConstraintID) { - LayoutConstraint layoutConstraint = - getLayoutConstraint(LayoutConstraintID, Context); - assert(layoutConstraint->isKnownLayout() && - "Expected layout constraint definition"); - - if (!layoutConstraint->isTrivial()) - return layoutConstraint; - - SourceLoc LParenLoc; - if (!consumeIf(tok::l_paren, LParenLoc)) { - // It is a trivial without any size constraints. - return LayoutConstraint::getLayoutConstraint(LayoutConstraintKind::Trivial, - Context); - } +/// Parse layout constraint for 'where' clause in '@_specialize' attribute +/// and in SIL. +/// +/// layout-constraint: +/// identifier +/// identifier '(' integer-literal ')' +/// identifier '(' integer-literal ',' integer-literal ')' +ParsedSyntaxResult +Parser::parseLayoutConstraintSyntax() { + assert(Tok.is(tok::identifier)); + ParsedLayoutConstraintSyntaxBuilder builder(*SyntaxContext); + + builder.useName(consumeTokenSyntax(tok::identifier)); + + if (!Tok.isFollowingLParen()) + return makeParsedResult(builder.build()); + + auto lParenLoc = Tok.getLoc(); + builder.useLeftParen(consumeTokenSyntax(tok::l_paren)); + + auto parseTrivialConstraintBody = [&]() -> bool { + int value; + + if (!Tok.is(tok::integer_literal) || + Tok.getText().getAsInteger(10, value) || value < 0) { + diagnose(Tok, diag::layout_size_should_be_positive); + return true; + } + builder.useSize(consumeTokenSyntax(tok::integer_literal)); - int size = 0; - int alignment = 0; + if (Tok.is(tok::comma)) { + builder.useComma(consumeTokenSyntax(tok::comma)); - auto ParseTrivialLayoutConstraintBody = [&] () -> bool { - // Parse the size and alignment. - if (Tok.is(tok::integer_literal)) { - if (Tok.getText().getAsInteger(10, size)) { - diagnose(Tok.getLoc(), diag::layout_size_should_be_positive); + if (!Tok.is(tok::integer_literal) || + Tok.getText().getAsInteger(10, value) || value < 0) { + diagnose(Tok, diag::layout_alignment_should_be_positive); return true; } - consumeToken(); - if (consumeIf(tok::comma)) { - // parse alignment. - if (Tok.is(tok::integer_literal)) { - if (Tok.getText().getAsInteger(10, alignment)) { - diagnose(Tok.getLoc(), diag::layout_alignment_should_be_positive); - return true; - } - consumeToken(); - } else { - diagnose(Tok.getLoc(), diag::layout_alignment_should_be_positive); - return true; - } - } - } else { - diagnose(Tok.getLoc(), diag::layout_size_should_be_positive); - return true; + builder.useAlignment(consumeTokenSyntax(tok::integer_literal)); } return false; }; - if (ParseTrivialLayoutConstraintBody()) { - // There was an error during parsing. - skipUntil(tok::r_paren); - consumeIf(tok::r_paren); - return LayoutConstraint::getUnknownLayout(); - } - - if (!consumeIf(tok::r_paren)) { - // Expected a closing r_paren. - diagnose(Tok.getLoc(), diag::expected_rparen_layout_constraint); - consumeToken(); - return LayoutConstraint::getUnknownLayout(); - } - - if (size < 0) { - diagnose(Tok.getLoc(), diag::layout_size_should_be_positive); - return LayoutConstraint::getUnknownLayout(); - } - - if (alignment < 0) { - diagnose(Tok.getLoc(), diag::layout_alignment_should_be_positive); - return LayoutConstraint::getUnknownLayout(); + if (parseTrivialConstraintBody()) { + ignoreUntil(tok::r_paren); + if (Tok.is(tok::r_paren)) + builder.useRightParen(consumeTokenSyntax(tok::r_paren)); + } else { + auto rParen = parseMatchingTokenSyntax(tok::r_paren, + diag::expected_rparen_layout_constraint, + lParenLoc); + if (rParen) + builder.useRightParen(std::move(*rParen)); } - - // Otherwise it is a trivial layout constraint with - // provided size and alignment. - return LayoutConstraint::getLayoutConstraint(layoutConstraint->getKind(), size, - alignment, Context); + return makeParsedResult(builder.build()); } /// parseTypeSimple @@ -369,7 +349,7 @@ Parser::TypeASTResult Parser::parseType(Diag<> MessageID, // the function body; otherwise, they are visible when parsing the type. if (!IsSILFuncDecl) GenericsScope.emplace(this, ScopeKind::Generics); - generics = maybeParseGenericParams().getPtrOrNull(); + generics = parseSILGenericParams().getPtrOrNull(); } // In SIL mode, parse box types { ... }. diff --git a/lib/Parse/ParsedSyntaxBuilders.cpp.gyb b/lib/Parse/ParsedSyntaxBuilders.cpp.gyb index 9ab3964f2b2cb..9306c0c8902f1 100644 --- a/lib/Parse/ParsedSyntaxBuilders.cpp.gyb +++ b/lib/Parse/ParsedSyntaxBuilders.cpp.gyb @@ -26,7 +26,7 @@ using namespace swift; using namespace swift::syntax; -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.is_buildable(): % for child in node.children: % child_elt = None diff --git a/lib/Parse/ParsedSyntaxNodes.cpp.gyb b/lib/Parse/ParsedSyntaxNodes.cpp.gyb index e3bb56c91812e..a21a0674a39e1 100644 --- a/lib/Parse/ParsedSyntaxNodes.cpp.gyb +++ b/lib/Parse/ParsedSyntaxNodes.cpp.gyb @@ -23,7 +23,7 @@ using namespace swift; using namespace swift::syntax; -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % for child in node.children: % if child.is_optional: Optional diff --git a/lib/Parse/ParsedSyntaxRecorder.cpp.gyb b/lib/Parse/ParsedSyntaxRecorder.cpp.gyb index b305e25e7cc8f..1e62ea13ba721 100644 --- a/lib/Parse/ParsedSyntaxRecorder.cpp.gyb +++ b/lib/Parse/ParsedSyntaxRecorder.cpp.gyb @@ -29,7 +29,7 @@ bool ParsedSyntaxRecorder::formExactLayoutFor(syntax::SyntaxKind Kind, MutableArrayRef Elements, function_ref)> receiver) { switch (Kind) { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: case SyntaxKind::${node.syntax_kind}: { % if node.children: % child_count = len(node.children) @@ -77,7 +77,7 @@ bool ParsedSyntaxRecorder::formExactLayoutFor(syntax::SyntaxKind Kind, } } -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.children: % child_params = [] % child_move_args = [] diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index f25a65fa096ef..7980fd39f1006 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -527,7 +527,7 @@ Parser::Parser(std::unique_ptr Lex, SourceFile &SF, L->getBufferID(), SF.SyntaxParsingCache, SF.getASTContext().getSyntaxArena())))), - Generator(SF.getASTContext(), &State) { + Generator(SF.getASTContext(), *this) { State = PersistentState; if (!State) { OwnedState.reset(new PersistentParserState()); diff --git a/lib/ParseSIL/ParseSIL.cpp b/lib/ParseSIL/ParseSIL.cpp index cededafc650aa..5915ef23758e6 100644 --- a/lib/ParseSIL/ParseSIL.cpp +++ b/lib/ParseSIL/ParseSIL.cpp @@ -3115,7 +3115,7 @@ bool SILParser::parseSILInstruction(SILBuilder &B) { SmallVector operandTypes; { Scope genericsScope(&P, ScopeKind::Generics); - generics = P.maybeParseGenericParams().getPtrOrNull(); + generics = P.parseSILGenericParams().getPtrOrNull(); patternEnv = handleSILGenericParams(P.Context, generics, &P.SF); if (P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "(")) @@ -5720,7 +5720,7 @@ bool SILParserTUState::parseSILProperty(Parser &P) { GenericEnvironment *patternEnv; Scope toplevelScope(&P, ScopeKind::TopLevel); Scope genericsScope(&P, ScopeKind::Generics); - generics = P.maybeParseGenericParams().getPtrOrNull(); + generics = P.parseSILGenericParams().getPtrOrNull(); patternEnv = handleSILGenericParams(P.Context, generics, &P.SF); if (patternEnv) { @@ -6033,7 +6033,7 @@ Optional SILParser::parseProtocolConformance( // Make sure we don't leave it uninitialized in the caller genericEnv = nullptr; - auto *genericParams = P.maybeParseGenericParams().getPtrOrNull(); + auto *genericParams = P.parseSILGenericParams().getPtrOrNull(); if (genericParams) { genericEnv = handleSILGenericParams(P.Context, genericParams, &P.SF); } diff --git a/lib/Syntax/SyntaxBuilders.cpp.gyb b/lib/Syntax/SyntaxBuilders.cpp.gyb index 8c93726dc5123..3a3af38751078 100644 --- a/lib/Syntax/SyntaxBuilders.cpp.gyb +++ b/lib/Syntax/SyntaxBuilders.cpp.gyb @@ -25,7 +25,7 @@ using namespace swift; using namespace swift::syntax; -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.is_buildable(): % for child in node.children: ${node.name}Builder & diff --git a/lib/Syntax/SyntaxFactory.cpp.gyb b/lib/Syntax/SyntaxFactory.cpp.gyb index dc6ad1a8c90dd..f7652bd83b5f8 100644 --- a/lib/Syntax/SyntaxFactory.cpp.gyb +++ b/lib/Syntax/SyntaxFactory.cpp.gyb @@ -63,7 +63,7 @@ SyntaxFactory::makeUnknownSyntax(llvm::ArrayRef Tokens, Syntax SyntaxFactory::makeBlankCollectionSyntax(SyntaxKind Kind) { switch(Kind) { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.is_syntax_collection(): case SyntaxKind::${node.syntax_kind}: return makeBlank${node.syntax_kind}(); % end @@ -76,7 +76,7 @@ Syntax SyntaxFactory::makeBlankCollectionSyntax(SyntaxKind Kind) { std::pair SyntaxFactory::countChildren(SyntaxKind Kind){ switch(Kind) { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if not node.is_syntax_collection(): case SyntaxKind::${node.syntax_kind}: % child_count = len(node.children) @@ -92,7 +92,7 @@ SyntaxFactory::countChildren(SyntaxKind Kind){ bool SyntaxFactory::canServeAsCollectionMemberRaw(SyntaxKind CollectionKind, SyntaxKind MemberKind) { switch (CollectionKind) { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.is_syntax_collection(): case SyntaxKind::${node.syntax_kind}: % if node.collection_element_choices: @@ -125,7 +125,7 @@ RC SyntaxFactory::createRaw(SyntaxKind Kind, llvm::ArrayRef> Elements, RC Arena) { switch (Kind) { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: case SyntaxKind::${node.syntax_kind}: { % if node.children: % child_count = len(node.children) @@ -178,7 +178,7 @@ Optional SyntaxFactory::createSyntax(SyntaxKind Kind, return None; } -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.children: % child_params = [] % for child in node.children: diff --git a/lib/Syntax/SyntaxKind.cpp.gyb b/lib/Syntax/SyntaxKind.cpp.gyb index 7603508970385..811c02ba3b14c 100644 --- a/lib/Syntax/SyntaxKind.cpp.gyb +++ b/lib/Syntax/SyntaxKind.cpp.gyb @@ -52,7 +52,7 @@ bool isTokenKeyword(tok kind) { bool parserShallOmitWhenNoChildren(syntax::SyntaxKind Kind) { switch(Kind) { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.shall_be_omitted_when_empty(): case syntax::SyntaxKind::${node.syntax_kind}: % end @@ -73,7 +73,7 @@ void dumpSyntaxKind(llvm::raw_ostream &os, const SyntaxKind kind) { case SyntaxKind::Unknown: os << "Unknown"; break; -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: case SyntaxKind::${node.syntax_kind}: os << "${node.syntax_kind}"; break; @@ -83,7 +83,7 @@ void dumpSyntaxKind(llvm::raw_ostream &os, const SyntaxKind kind) { bool isCollectionKind(SyntaxKind Kind) { switch(Kind) { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.is_syntax_collection(): case SyntaxKind::${node.syntax_kind}: % end @@ -147,7 +147,7 @@ SyntaxKind getUnknownKind(SyntaxKind Kind) { llvm::raw_ostream &llvm::operator<<(llvm::raw_ostream &OS, swift::syntax::SyntaxKind Kind) { switch (Kind) { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: case swift::syntax::SyntaxKind::${node.syntax_kind}: OS << "${node.syntax_kind}"; break; diff --git a/lib/Syntax/SyntaxNodes.cpp.gyb b/lib/Syntax/SyntaxNodes.cpp.gyb index 34418e182f1ca..e3302f3389914 100644 --- a/lib/Syntax/SyntaxNodes.cpp.gyb +++ b/lib/Syntax/SyntaxNodes.cpp.gyb @@ -24,7 +24,7 @@ using namespace swift; using namespace swift::syntax; -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if node.requires_validation(): void ${node.name}::validate() const { #ifndef NDEBUG diff --git a/lib/Syntax/SyntaxVisitor.cpp.gyb b/lib/Syntax/SyntaxVisitor.cpp.gyb index 722ab5d46f4e7..14e92d72c1995 100644 --- a/lib/Syntax/SyntaxVisitor.cpp.gyb +++ b/lib/Syntax/SyntaxVisitor.cpp.gyb @@ -21,7 +21,7 @@ #include "swift/Syntax/SyntaxVisitor.h" #include "swift/Basic/Defer.h" -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if is_visitable(node): void swift::syntax::SyntaxVisitor::visit(${node.name} node) { visitChildren(node); @@ -36,7 +36,7 @@ void swift::syntax::SyntaxVisitor::visit(Syntax node) { case SyntaxKind::Token: visit(node.castTo()); return; -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + SILONLY_NODES: % if is_visitable(node): case SyntaxKind::${node.syntax_kind}: visit(node.castTo<${node.name}>()); diff --git a/test/Parse/invalid.swift b/test/Parse/invalid.swift index 7a290d5c8b669..097588b54f695 100644 --- a/test/Parse/invalid.swift +++ b/test/Parse/invalid.swift @@ -124,7 +124,7 @@ prefix func %(x: T) -> T { return x } // No error expected - the < is conside struct Weak { // expected-error {{'class' constraint can only appear on protocol declarations}} // expected-note@-1 {{did you mean to write an 'AnyObject' constraint?}} {{16-21=AnyObject}} - weak let value: T // expected-error {{'weak' must be a mutable variable, because it may change at runtime}} expected-error {{'weak' variable should have optional type 'T?'}} expected-error {{'weak' must not be applied to non-class-bound 'T'; consider adding a protocol conformance that has a class bound}} + weak let value: T // expected-error {{'weak' must be a mutable variable, because it may change at runtime}} expected-error {{'weak' variable should have optional type 'T?'}} } let x: () = () diff --git a/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds b/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds index 6a687bae4e8c9..680d7b2d4cae4 100644 --- a/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds +++ b/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds @@ -121,7 +121,7 @@ protocol PP { associatedtype B: Sequence associatedtype C = Int associatedtype D: Sequence = [Int] - associatedtype E: Sequence = [[Int]] where A.Element : Sequence + associatedtype E: Sequence = [[Int]] where A.Element : Sequence private associatedtype F @objc associatedtype G } @@ -155,7 +155,7 @@ class Bar: Foo foo: Int = 42 } -class C<A, B> where A: Foo, B == Bar {} +class C<A, B> where A: Foo, B == Bar {} @available(*, unavailable) private class C {} @@ -183,9 +183,9 @@ struct foo { } } -struct S<A, B, C, @objc D> where A:B, B==C, A : C, B.C == D.A, A.B: C.D {} +struct S<A, B, C, @objc D> where A:B, B==C, A : C, B.C == D.A, A.B: C.D {} -private struct S<A, B>: Base where A: B { +private struct S<A, B>: Base where A: B { private struct S: A, B {} } @@ -205,18 +205,18 @@ func foo( a: { @objc @available(*, unavailable) -private static override func foo<a, b, c>(a b: Int, c: Int) throws -> [Int] where a==p1, b:p2 { ddd } +private static override func foo<a, b, c>(a b: Int, c: Int) throws -> [Int] where a==p1, b:p2 { ddd } func rootView() -> Label {} static func ==() -> bool {} static func !=<a, b, c>() -> bool {} } @objc -private protocol foo : bar where A==B {} +private protocol foo : bar where A==B {} protocol foo { func foo() } private protocol foo{} @objc -public protocol foo where A:B {} +public protocol foo where A:B {} #if blah func tryfoo() { @@ -431,7 +431,7 @@ fileprivate extension ext ext : extProtocol {} -extension ext where A == Int, B: Numeric {} +extension ext where A == Int, B: Numeric {} extension ext.a.b {} @@ -478,7 +478,7 @@ enum E1 : String bar = "test", baz(x: Int, String) = 12 indirect case qux(E1) - indirect private enum E2<T>: String where T: SomeProtocol { + indirect private enum E2<T>: String where T: SomeProtocol { case foo, bar, baz } } @@ -507,8 +507,8 @@ func higherOrderFunc() #available(iOS 11, macOS 10.11.2, *) {} -@_specialize(where T == Int) -@_specialize(exported: true, where T == String) +@_specialize(where T == Int) +@_specialize(exported: true, where T == String) public func specializedGenericFunc<T>(_ t: T) -> T { return t } diff --git a/unittests/Syntax/DeclSyntaxTests.cpp b/unittests/Syntax/DeclSyntaxTests.cpp index 5f29d564442fa..bc13978633314 100644 --- a/unittests/Syntax/DeclSyntaxTests.cpp +++ b/unittests/Syntax/DeclSyntaxTests.cpp @@ -550,11 +550,11 @@ GenericWhereClauseSyntax getCannedWhereClause() { auto T = SyntaxFactory::makeTypeIdentifier("T", {}, Trivia::spaces(1)); auto EqualEqual = SyntaxFactory::makeEqualityOperator({}, Trivia::spaces(1)); auto Int = SyntaxFactory::makeTypeIdentifier("Int", {}, Trivia::spaces(1)); - auto SameType = SyntaxFactory::makeSameTypeRequirement(T, EqualEqual, Int, - None); + auto SameType = SyntaxFactory::makeSameTypeRequirement(T, EqualEqual, Int); + auto Req = SyntaxFactory::makeGenericRequirement(SameType, None); auto Requirements = SyntaxFactory::makeBlankGenericRequirementList() - .appending(SameType); + .appending(Req); return SyntaxFactory::makeBlankGenericWhereClause() .withWhereKeyword(WhereKW) diff --git a/utils/gyb_syntax_support/GenericNodes.py b/utils/gyb_syntax_support/GenericNodes.py index e93a80b3bfe05..afb6a4af2e99d 100644 --- a/utils/gyb_syntax_support/GenericNodes.py +++ b/utils/gyb_syntax_support/GenericNodes.py @@ -11,22 +11,39 @@ ]), Node('GenericRequirementList', kind='SyntaxCollection', - element='Syntax', + element='GenericRequirement', element_name='GenericRequirement'), + # generic-requirement -> + # (same-type-requrement|conformance-requirement|layout-requirement) ','? + Node('GenericRequirement', kind='Syntax', + traits=['WithTrailingComma'], + children=[ + Child('Body', kind='Syntax', + node_choices=[ + Child('SameTypeRequirement', + kind='SameTypeRequirement'), + Child('ConformanceRequirement', + kind='ConformanceRequirement'), + Child('LayoutRequirement', + kind='LayoutRequirement'), + ]), + Child('TrailingComma', kind='CommaToken', + is_optional=True), + ]), + # same-type-requirement -> type-identifier == type Node('SameTypeRequirement', kind='Syntax', - traits=['WithTrailingComma'], children=[ Child('LeftTypeIdentifier', kind='Type'), Child('EqualityToken', kind='Token', token_choices=[ 'SpacedBinaryOperatorToken', 'UnspacedBinaryOperatorToken', + 'PrefixOperatorToken', + 'PostfixOperatorToken', ]), Child('RightTypeIdentifier', kind='Type'), - Child('TrailingComma', kind='CommaToken', - is_optional=True), ]), Node('GenericParameterList', kind='SyntaxCollection', @@ -55,17 +72,41 @@ Child('LeftAngleBracket', kind='LeftAngleToken'), Child('GenericParameterList', kind='GenericParameterList', collection_element_name='GenericParameter'), + Child('ObsoletedWhereClause', kind='GenericWhereClause', + is_optional=True), Child('RightAngleBracket', kind='RightAngleToken'), ]), # conformance-requirement -> type-identifier : type-identifier Node('ConformanceRequirement', kind='Syntax', - traits=['WithTrailingComma'], children=[ Child('LeftTypeIdentifier', kind='Type'), Child('Colon', kind='ColonToken'), Child('RightTypeIdentifier', kind='Type'), - Child('TrailingComma', kind='CommaToken', - is_optional=True), + ]), + + # layout-requirement -> type ':' layout-constraint + Node('LayoutRequirement', kind='Syntax', + children=[ + Child('LeftTypeIdentifier', kind='Type'), + Child('Colon', kind='ColonToken'), + Child('LayoutConstraint', kind='LayoutConstraint'), + ]), + + # layout-constraint -> + # identifier ('(' integer-literal (',' integer-literal)? ')')? + Node('LayoutConstraint', kind='Syntax', + children=[ + Child('Name', kind='IdentifierToken'), + Child('LeftParen', kind='LeftParenToken', + is_optional=True), + Child('Size', kind='IntegerLiteralToken', + is_optional=True), + Child('Comma', kind='CommaToken', + is_optional=True), + Child('Alignment', kind='IntegerLiteralToken', + is_optional=True), + Child('RightParen', kind='RightParenToken', + is_optional=True), ]), ] diff --git a/utils/gyb_syntax_support/NodeSerializationCodes.py b/utils/gyb_syntax_support/NodeSerializationCodes.py index 4bacc660f7cbc..fb9edd7ca3e40 100644 --- a/utils/gyb_syntax_support/NodeSerializationCodes.py +++ b/utils/gyb_syntax_support/NodeSerializationCodes.py @@ -233,6 +233,9 @@ 'PoundAssertStmt': 229, 'SomeType': 230, 'CustomAttribute': 231, + 'GenericRequirement': 232, + 'LayoutRequirement': 233, + 'LayoutConstraint': 234, } diff --git a/utils/gyb_syntax_support/SILOnlyNodes.py b/utils/gyb_syntax_support/SILOnlyNodes.py new file mode 100644 index 0000000000000..799ca5c99ee56 --- /dev/null +++ b/utils/gyb_syntax_support/SILOnlyNodes.py @@ -0,0 +1,9 @@ +from Node import Node # noqa: I201 + +# These nodes are used only in SIL parsing. + +SILONLY_NODES = [ + # generic-parameter-clause-list + Node('GenericParameterClauseList', kind='SyntaxCollection', + element='GenericParameterClause'), +] diff --git a/utils/gyb_syntax_support/__init__.py b/utils/gyb_syntax_support/__init__.py index 6f32da7920fa7..437ce147b321c 100644 --- a/utils/gyb_syntax_support/__init__.py +++ b/utils/gyb_syntax_support/__init__.py @@ -11,6 +11,7 @@ verify_syntax_node_serialization_codes from PatternNodes import PATTERN_NODES # noqa: I201 +from SILOnlyNodes import SILONLY_NODES # noqa: I201 from StmtNodes import STMT_NODES # noqa: I201 import Token from Trivia import TRIVIAS # noqa: I201 From 1861536e3eeb90b0872940c946cd2143c94566d1 Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Fri, 20 Sep 2019 15:26:37 -0700 Subject: [PATCH 121/199] [Syntax] Fix Python lint failure --- utils/gyb_syntax_support/GenericNodes.py | 22 ++++----- utils/gyb_syntax_support/Node.py | 4 +- utils/gyb_syntax_support/__init__.py | 62 ++++++++++++++++-------- 3 files changed, 57 insertions(+), 31 deletions(-) diff --git a/utils/gyb_syntax_support/GenericNodes.py b/utils/gyb_syntax_support/GenericNodes.py index afb6a4af2e99d..61fd4cf0723ff 100644 --- a/utils/gyb_syntax_support/GenericNodes.py +++ b/utils/gyb_syntax_support/GenericNodes.py @@ -97,16 +97,16 @@ # identifier ('(' integer-literal (',' integer-literal)? ')')? Node('LayoutConstraint', kind='Syntax', children=[ - Child('Name', kind='IdentifierToken'), - Child('LeftParen', kind='LeftParenToken', - is_optional=True), - Child('Size', kind='IntegerLiteralToken', - is_optional=True), - Child('Comma', kind='CommaToken', - is_optional=True), - Child('Alignment', kind='IntegerLiteralToken', - is_optional=True), - Child('RightParen', kind='RightParenToken', - is_optional=True), + Child('Name', kind='IdentifierToken'), + Child('LeftParen', kind='LeftParenToken', + is_optional=True), + Child('Size', kind='IntegerLiteralToken', + is_optional=True), + Child('Comma', kind='CommaToken', + is_optional=True), + Child('Alignment', kind='IntegerLiteralToken', + is_optional=True), + Child('RightParen', kind='RightParenToken', + is_optional=True), ]), ] diff --git a/utils/gyb_syntax_support/Node.py b/utils/gyb_syntax_support/Node.py index ab8320dc5765e..e60628837ed7a 100644 --- a/utils/gyb_syntax_support/Node.py +++ b/utils/gyb_syntax_support/Node.py @@ -1,5 +1,7 @@ from __future__ import print_function -import sys # noqa: I201 + +import sys + from kinds import SYNTAX_BASE_KINDS, kind_to_type, lowercase_first_word diff --git a/utils/gyb_syntax_support/__init__.py b/utils/gyb_syntax_support/__init__.py index 437ce147b321c..632e05429f5ca 100644 --- a/utils/gyb_syntax_support/__init__.py +++ b/utils/gyb_syntax_support/__init__.py @@ -1,30 +1,54 @@ import textwrap -from AttributeNodes import ATTRIBUTE_NODES # noqa: I201 -from AvailabilityNodes import AVAILABILITY_NODES # noqa: I201 -import Classification # noqa: I201 -from CommonNodes import COMMON_NODES # noqa: I201 -from DeclNodes import DECL_NODES # noqa: I201 -from ExprNodes import EXPR_NODES # noqa: I201 -from GenericNodes import GENERIC_NODES # noqa: I201 -from NodeSerializationCodes import SYNTAX_NODE_SERIALIZATION_CODES, \ + +from . import Token +from .AttributeNodes import ATTRIBUTE_NODES +from .AvailabilityNodes import AVAILABILITY_NODES +from .Classification import SYNTAX_CLASSIFICATIONS +from .CommonNodes import COMMON_NODES +from .DeclNodes import DECL_NODES +from .ExprNodes import EXPR_NODES +from .GenericNodes import GENERIC_NODES +from .NodeSerializationCodes import SYNTAX_NODE_SERIALIZATION_CODES, \ get_serialization_code, \ verify_syntax_node_serialization_codes - -from PatternNodes import PATTERN_NODES # noqa: I201 -from SILOnlyNodes import SILONLY_NODES # noqa: I201 -from StmtNodes import STMT_NODES # noqa: I201 -import Token -from Trivia import TRIVIAS # noqa: I201 -from TypeNodes import TYPE_NODES # noqa: I201 +from .PatternNodes import PATTERN_NODES +from .SILOnlyNodes import SILONLY_NODES +from .StmtNodes import STMT_NODES +from .Token import SYNTAX_TOKENS, SYNTAX_TOKEN_MAP +from .Trivia import TRIVIAS +from .TypeNodes import TYPE_NODES + +__all__ = [ + 'Token', + 'AVAILABILITY_NODES', + 'SYNTAX_CLASSIFICATIONS', + 'COMMON_NODES', + 'DECL_NODES', + 'EXPR_NODES', + 'GENERIC_NODES', + 'SYNTAX_NODE_SERIALIZATION_CODES', + 'PATTERN_NODES', + 'SILONLY_NODES', + 'STMT_NODES', + 'SYNTAX_TOKENS', + 'SYNTAX_TOKEN_MAP', + 'TRIVIAS', + 'TYPE_NODES', + 'SYNTAX_NODES', + 'make_missing_child', + 'check_child_condition_raw', + 'check_parsed_child_condition_raw', + 'make_missing_swift_child', + 'create_node_map', + 'is_visitable', + 'dedented_lines', + 'calculate_node_hash', +] -# Re-export global constants SYNTAX_NODES = COMMON_NODES + EXPR_NODES + DECL_NODES + ATTRIBUTE_NODES + \ STMT_NODES + GENERIC_NODES + TYPE_NODES + PATTERN_NODES + \ AVAILABILITY_NODES -SYNTAX_TOKENS = Token.SYNTAX_TOKENS -SYNTAX_TOKEN_MAP = Token.SYNTAX_TOKEN_MAP -SYNTAX_CLASSIFICATIONS = Classification.SYNTAX_CLASSIFICATIONS verify_syntax_node_serialization_codes(SYNTAX_NODES, SYNTAX_NODE_SERIALIZATION_CODES) From b32ef852feb73661ad59de9f394bd5c7d519a95f Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Fri, 20 Sep 2019 16:59:27 -0700 Subject: [PATCH 122/199] [ClangImporter] Remove workaround for old NS_ERROR_ENUM import logic (#27267) At one point the enum in an NS_ERROR_ENUM would get mapped to the struct that the ClangImporter synthesized for it, rather than the code enum that directly corresponded to what was declared in Objective-C. That's not how the importer works anymore, though; we can trust that the right type is picked without additional adjustments. --- lib/ClangImporter/ImportType.cpp | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index 08f9de2ee05e7..4d581609329fe 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -663,7 +663,7 @@ namespace { // If that fails, fall back on importing the underlying type. if (!decl) return Visit(type->desugar()); - Type mappedType = getAdjustedTypeDeclReferenceType(decl); + Type mappedType = decl->getDeclaredInterfaceType(); if (getSwiftNewtypeAttr(type->getDecl(), Impl.CurrentVersion)) { if (isCFTypeDecl(type->getDecl())) { @@ -816,19 +816,6 @@ namespace { if (!decl) return nullptr; - return getAdjustedTypeDeclReferenceType(decl); - } - - /// Retrieve the adjusted type of a reference to the given type declaration. - Type getAdjustedTypeDeclReferenceType(TypeDecl *decl) { - // If the imported declaration is a bridged NSError, dig out - // the Code nested type. References to the enum type from C - // code need to map to the code type (which is ABI compatible with C), - // and the bridged error type is used elsewhere. - if (auto *structDecl = dyn_cast(decl)) - if (auto *codeEnum = Impl.lookupErrorCodeEnum(structDecl)) - return codeEnum->getDeclaredInterfaceType(); - return decl->getDeclaredInterfaceType(); } @@ -861,7 +848,7 @@ namespace { if (!decl) return nullptr; - return getAdjustedTypeDeclReferenceType(decl); + return decl->getDeclaredInterfaceType(); } } From 27e881d97e63125f7cb96eb119b10a99eac4fa15 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Fri, 20 Sep 2019 17:01:44 -0700 Subject: [PATCH 123/199] [AST] Shrink CaptureInfo down to a PointerIntPair (#27261) If there are any actual captures, a CaptureInfoStorage will be allocated in the ASTContext, matching the previous behavior of allocating the array of captures there. No functionality change. I /tried/ to change the functionality to assert everywhere capture info was used but hadn't explicitly been computed, but it turns out we do that /all over the place/ for any declaration that's been synthesized, imported, or deserialized. I left in some groundwork for someone to make this more explicit (or requestify it) in the future. --- include/swift/AST/CaptureInfo.h | 102 +++++++++++++++++++++----------- lib/AST/CaptureInfo.cpp | 41 ++++++++++++- lib/SIL/TypeLowering.cpp | 13 ++-- lib/Sema/TypeCheckCaptures.cpp | 57 ++++++++---------- 4 files changed, 137 insertions(+), 76 deletions(-) diff --git a/include/swift/AST/CaptureInfo.h b/include/swift/AST/CaptureInfo.h index d8e699ed6c99a..1eeaecd27f8a0 100644 --- a/include/swift/AST/CaptureInfo.h +++ b/include/swift/AST/CaptureInfo.h @@ -14,11 +14,13 @@ #define SWIFT_AST_CAPTURE_INFO_H #include "swift/Basic/LLVM.h" +#include "swift/Basic/OptionSet.h" #include "swift/Basic/SourceLoc.h" #include "swift/AST/TypeAlignments.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/PointerUnion.h" +#include "llvm/Support/TrailingObjects.h" #include namespace swift { @@ -114,31 +116,63 @@ class DynamicSelfType; /// Stores information about captured variables. class CaptureInfo { - const CapturedValue *Captures; - DynamicSelfType *DynamicSelf; - OpaqueValueExpr *OpaqueValue; - unsigned Count = 0; - bool GenericParamCaptures : 1; - bool Computed : 1; + class CaptureInfoStorage final + : public llvm::TrailingObjects { + + DynamicSelfType *DynamicSelf; + OpaqueValueExpr *OpaqueValue; + unsigned Count; + public: + explicit CaptureInfoStorage(unsigned count, DynamicSelfType *dynamicSelf, + OpaqueValueExpr *opaqueValue) + : DynamicSelf(dynamicSelf), OpaqueValue(opaqueValue), Count(count) { } + + ArrayRef getCaptures() const { + return llvm::makeArrayRef(this->getTrailingObjects(), + Count); + } + + DynamicSelfType *getDynamicSelfType() const { + return DynamicSelf; + } + + OpaqueValueExpr *getOpaqueValue() const { + return OpaqueValue; + } + }; + + enum class Flags : unsigned { + HasGenericParamCaptures = 1 << 0 + }; + + llvm::PointerIntPair> + StorageAndFlags; public: - CaptureInfo() - : Captures(nullptr), DynamicSelf(nullptr), OpaqueValue(nullptr), Count(0), - GenericParamCaptures(0), Computed(0) { } + /// The default-constructed CaptureInfo is "not yet computed". + CaptureInfo() = default; + CaptureInfo(ASTContext &ctx, ArrayRef captures, + DynamicSelfType *dynamicSelf, OpaqueValueExpr *opaqueValue, + bool genericParamCaptures); - bool hasBeenComputed() const { return Computed; } + /// A CaptureInfo representing no captures at all. + static CaptureInfo empty(); + + bool hasBeenComputed() const { + return StorageAndFlags.getPointer(); + } bool isTrivial() const { - return Count == 0 && !GenericParamCaptures && !DynamicSelf && !OpaqueValue; + return getCaptures().empty() && !hasGenericParamCaptures() && + !hasDynamicSelfCapture() && !hasOpaqueValueCapture(); } ArrayRef getCaptures() const { - return llvm::makeArrayRef(Captures, Count); - } - void setCaptures(ArrayRef C) { - Captures = C.data(); - Computed = true; - Count = C.size(); + // FIXME: Ideally, everywhere that synthesizes a function should include + // its capture info. + if (!hasBeenComputed()) + return None; + return StorageAndFlags.getPointer()->getCaptures(); } /// Return a filtered list of the captures for this function, @@ -152,37 +186,37 @@ class CaptureInfo { /// \returns true if the function captures any generic type parameters. bool hasGenericParamCaptures() const { - return GenericParamCaptures; - } - - void setGenericParamCaptures(bool genericParamCaptures) { - GenericParamCaptures = genericParamCaptures; + // FIXME: Ideally, everywhere that synthesizes a function should include + // its capture info. + if (!hasBeenComputed()) + return false; + return StorageAndFlags.getInt().contains(Flags::HasGenericParamCaptures); } /// \returns true if the function captures the dynamic Self type. bool hasDynamicSelfCapture() const { - return DynamicSelf != nullptr; + return getDynamicSelfType() != nullptr; } /// \returns the captured dynamic Self type, if any. DynamicSelfType *getDynamicSelfType() const { - return DynamicSelf; - } - - void setDynamicSelfType(DynamicSelfType *dynamicSelf) { - DynamicSelf = dynamicSelf; + // FIXME: Ideally, everywhere that synthesizes a function should include + // its capture info. + if (!hasBeenComputed()) + return nullptr; + return StorageAndFlags.getPointer()->getDynamicSelfType(); } bool hasOpaqueValueCapture() const { - return OpaqueValue != nullptr; + return getOpaqueValue() != nullptr; } OpaqueValueExpr *getOpaqueValue() const { - return OpaqueValue; - } - - void setOpaqueValue(OpaqueValueExpr *OVE) { - OpaqueValue = OVE; + // FIXME: Ideally, everywhere that synthesizes a function should include + // its capture info. + if (!hasBeenComputed()) + return nullptr; + return StorageAndFlags.getPointer()->getOpaqueValue(); } void dump() const; diff --git a/lib/AST/CaptureInfo.cpp b/lib/AST/CaptureInfo.cpp index de209b3558a4b..ea641857d8693 100644 --- a/lib/AST/CaptureInfo.cpp +++ b/lib/AST/CaptureInfo.cpp @@ -11,11 +11,50 @@ //===----------------------------------------------------------------------===// #include "swift/AST/CaptureInfo.h" +#include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "llvm/Support/raw_ostream.h" using namespace swift; +CaptureInfo::CaptureInfo(ASTContext &ctx, ArrayRef captures, + DynamicSelfType *dynamicSelf, + OpaqueValueExpr *opaqueValue, + bool genericParamCaptures) { + static_assert(IsTriviallyDestructible::value, + "Capture info is alloc'd on the ASTContext and not destroyed"); + static_assert(IsTriviallyDestructible::value, + "Capture info is alloc'd on the ASTContext and not destroyed"); + + OptionSet flags; + if (genericParamCaptures) + flags |= Flags::HasGenericParamCaptures; + + if (captures.empty() && !dynamicSelf && !opaqueValue) { + *this = CaptureInfo::empty(); + StorageAndFlags.setInt(flags); + return; + } + + size_t storageToAlloc = + CaptureInfoStorage::totalSizeToAlloc(captures.size()); + void *storageBuf = ctx.Allocate(storageToAlloc, alignof(CaptureInfoStorage)); + auto *storage = new (storageBuf) CaptureInfoStorage(captures.size(), + dynamicSelf, + opaqueValue); + StorageAndFlags.setPointerAndInt(storage, flags); + std::uninitialized_copy(captures.begin(), captures.end(), + storage->getTrailingObjects()); +} + +CaptureInfo CaptureInfo::empty() { + static const CaptureInfoStorage empty{0, /*dynamicSelf*/nullptr, + /*opaqueValue*/nullptr}; + CaptureInfo result; + result.StorageAndFlags.setPointer(&empty); + return result; +} + bool CaptureInfo::hasLocalCaptures() const { for (auto capture : getCaptures()) if (capture.getDecl()->getDeclContext()->isLocalContext()) @@ -28,7 +67,7 @@ void CaptureInfo:: getLocalCaptures(SmallVectorImpl &Result) const { if (!hasLocalCaptures()) return; - Result.reserve(Count); + Result.reserve(getCaptures().size()); // Filter out global variables. for (auto capture : getCaptures()) { diff --git a/lib/SIL/TypeLowering.cpp b/lib/SIL/TypeLowering.cpp index cc79428694489..ba537bc743b43 100644 --- a/lib/SIL/TypeLowering.cpp +++ b/lib/SIL/TypeLowering.cpp @@ -2310,15 +2310,12 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) { } // Cache the uniqued set of transitive captures. - auto inserted = LoweredCaptures.insert({fn, CaptureInfo()}); + CaptureInfo info{Context, resultingCaptures, capturesDynamicSelf, + capturesOpaqueValue, capturesGenericParams}; + auto inserted = LoweredCaptures.insert({fn, info}); assert(inserted.second && "already in map?!"); - auto &cachedCaptures = inserted.first->second; - cachedCaptures.setGenericParamCaptures(capturesGenericParams); - cachedCaptures.setDynamicSelfType(capturesDynamicSelf); - cachedCaptures.setOpaqueValue(capturesOpaqueValue); - cachedCaptures.setCaptures(Context.AllocateCopy(resultingCaptures)); - - return cachedCaptures; + (void)inserted; + return info; } /// Given that type1 is known to be a subtype of type2, check if the two diff --git a/lib/Sema/TypeCheckCaptures.cpp b/lib/Sema/TypeCheckCaptures.cpp index 9cf5f41b1b99e..048bff537ff1d 100644 --- a/lib/Sema/TypeCheckCaptures.cpp +++ b/lib/Sema/TypeCheckCaptures.cpp @@ -42,39 +42,33 @@ class FindCapturedVars : public ASTWalker { OpaqueValueExpr *OpaqueValue = nullptr; SourceLoc CaptureLoc; DeclContext *CurDC; - bool NoEscape, ObjC; + bool NoEscape, ObjC, IsGenericFunction; public: FindCapturedVars(ASTContext &Context, SourceLoc CaptureLoc, DeclContext *CurDC, bool NoEscape, - bool ObjC) + bool ObjC, + bool IsGenericFunction) : Context(Context), CaptureLoc(CaptureLoc), CurDC(CurDC), - NoEscape(NoEscape), ObjC(ObjC) {} + NoEscape(NoEscape), ObjC(ObjC), IsGenericFunction(IsGenericFunction) {} CaptureInfo getCaptureInfo() const { - CaptureInfo result; - - // Anything can capture an opaque value placeholder. - if (OpaqueValue) - result.setOpaqueValue(OpaqueValue); + DynamicSelfType *dynamicSelfToRecord = nullptr; + bool hasGenericParamCaptures = IsGenericFunction; // Only local functions capture dynamic 'Self'. if (CurDC->getParent()->isLocalContext()) { if (GenericParamCaptureLoc.isValid()) - result.setGenericParamCaptures(true); + hasGenericParamCaptures = true; if (DynamicSelfCaptureLoc.isValid()) - result.setDynamicSelfType(DynamicSelf); + dynamicSelfToRecord = DynamicSelf; } - if (Captures.empty()) - result.setCaptures(None); - else - result.setCaptures(Context.AllocateCopy(Captures)); - - return result; + return CaptureInfo(Context, Captures, dynamicSelfToRecord, OpaqueValue, + hasGenericParamCaptures); } SourceLoc getGenericParamCaptureLoc() const { @@ -590,28 +584,26 @@ void TypeChecker::computeCaptures(AnyFunctionRef AFR) { PrettyStackTraceAnyFunctionRef trace("computing captures for", AFR); + // A generic function always captures outer generic parameters. + bool isGeneric = false; + auto *AFD = AFR.getAbstractFunctionDecl(); + if (AFD) + isGeneric = (AFD->getGenericParams() != nullptr); + auto &Context = AFR.getAsDeclContext()->getASTContext(); FindCapturedVars finder(Context, AFR.getLoc(), AFR.getAsDeclContext(), AFR.isKnownNoEscape(), - AFR.isObjC()); + AFR.isObjC(), + isGeneric); AFR.getBody()->walk(finder); if (AFR.hasType() && !AFR.isObjC()) { finder.checkType(AFR.getType(), AFR.getLoc()); } - // A generic function always captures outer generic parameters. - bool isGeneric = false; - auto *AFD = AFR.getAbstractFunctionDecl(); - if (AFD) - isGeneric = AFD->isGeneric(); - - auto captures = finder.getCaptureInfo(); - if (isGeneric) - captures.setGenericParamCaptures(true); - AFR.setCaptureInfo(captures); + AFR.setCaptureInfo(finder.getCaptureInfo()); // Compute captures for default argument expressions. if (auto *AFD = AFR.getAbstractFunctionDecl()) { @@ -621,7 +613,8 @@ void TypeChecker::computeCaptures(AnyFunctionRef AFR) { E->getLoc(), AFD, /*isNoEscape=*/false, - /*isObjC=*/false); + /*isObjC=*/false, + /*IsGeneric*/isGeneric); E->walk(finder); if (!AFD->getDeclContext()->isLocalContext() && @@ -630,10 +623,7 @@ void TypeChecker::computeCaptures(AnyFunctionRef AFR) { diag::dynamic_self_default_arg); } - auto captures = finder.getCaptureInfo(); - if (isGeneric) - captures.setGenericParamCaptures(true); - P->setDefaultArgumentCaptureInfo(captures); + P->setDefaultArgumentCaptureInfo(finder.getCaptureInfo()); } } } @@ -690,7 +680,8 @@ void TypeChecker::checkPatternBindingCaptures(NominalTypeDecl *typeDecl) { init->getLoc(), PBD->getInitContext(i), /*NoEscape=*/false, - /*ObjC=*/false); + /*ObjC=*/false, + /*IsGenericFunction*/false); init->walk(finder); if (finder.getDynamicSelfCaptureLoc().isValid() && !isLazy(PBD)) { From 2b25fe0ef20c73b1dd28812e8e19839bed192b6a Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Thu, 19 Sep 2019 17:42:37 -0700 Subject: [PATCH 124/199] [ClangImporter] Remove now-unnecessary special case for IUO importing Back when IUO could be used anywhere in a type in Swift, we had a special case for imported pointer types that their pointees were never implicitly-unwrapped, even if they weren't nullability-audited on the Objective-C side. Now that IUO can only be used in top-level positions (SE-0054, only fully implemented last year), we don't need a special case for this; all non-top-level optionals are never implicitly-unwrapped. No functionality change. --- lib/ClangImporter/ImportType.cpp | 23 ++++------------------- lib/ClangImporter/ImporterImpl.h | 7 ------- 2 files changed, 4 insertions(+), 26 deletions(-) diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index 694e32a9586b4..22ab1745e584c 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -160,15 +160,6 @@ namespace { explicit operator bool() const { return (bool) AbstractType; } }; - static OptionalTypeKind getOptionalKind(ImportTypeKind kind, - OptionalTypeKind OptKind) { - // Import pointee types as true Optional. - if (OptKind == OTK_ImplicitlyUnwrappedOptional && - kind == ImportTypeKind::Pointee) - return OTK_Optional; - return OptKind; - } - class SwiftTypeConverter : public clang::TypeVisitor { @@ -393,7 +384,7 @@ namespace { pointeeType = Impl.getNamedSwiftType(Impl.getStdlibModule(), "Void"); else pointeeType = Impl.importTypeIgnoreIUO( - pointeeQualType, ImportTypeKind::Pointee, AllowNSUIntegerAsInt, + pointeeQualType, ImportTypeKind::Value, AllowNSUIntegerAsInt, Bridgeability::None); // If the pointed-to type is unrepresentable in Swift, or its C @@ -479,7 +470,7 @@ namespace { // we can cheese static-offset "indexing" using .$n operations. Type elementType = Impl.importTypeIgnoreIUO( - type->getElementType(), ImportTypeKind::Pointee, AllowNSUIntegerAsInt, + type->getElementType(), ImportTypeKind::Value, AllowNSUIntegerAsInt, Bridgeability::None); if (!elementType) return Type(); @@ -1096,7 +1087,6 @@ static bool canBridgeTypes(ImportTypeKind importKind) { case ImportTypeKind::Value: case ImportTypeKind::Variable: case ImportTypeKind::AuditedVariable: - case ImportTypeKind::Pointee: case ImportTypeKind::Enum: case ImportTypeKind::RecordField: return false; @@ -1124,7 +1114,6 @@ static bool isCFAudited(ImportTypeKind importKind) { case ImportTypeKind::ObjCCollectionElement: case ImportTypeKind::Variable: case ImportTypeKind::Result: - case ImportTypeKind::Pointee: case ImportTypeKind::Enum: case ImportTypeKind::RecordField: return false; @@ -1398,7 +1387,6 @@ static ImportedType adjustTypeForConcreteImport( // optional type. bool isIUO = false; if (importKind != ImportTypeKind::Typedef && canImportAsOptional(hint)) { - optKind = getOptionalKind(importKind, optKind); isIUO = optKind == OTK_ImplicitlyUnwrappedOptional; if (optKind != OTK_None) importedType = OptionalType::get(importedType); @@ -2044,14 +2032,11 @@ ImportedType ClangImporter::Implementation::importMethodType( bool paramIsIUO; if (kind == SpecialMethodKind::NSDictionarySubscriptGetter && paramTy->isObjCIdType()) { - auto optKind = - getOptionalKind(ImportTypeKind::Parameter, optionalityOfParam); - swiftParamTy = SwiftContext.getNSCopyingDecl()->getDeclaredType(); - if (optKind != OTK_None) + if (optionalityOfParam != OTK_None) swiftParamTy = OptionalType::get(swiftParamTy); - paramIsIUO = optKind == OTK_ImplicitlyUnwrappedOptional; + paramIsIUO = optionalityOfParam == OTK_ImplicitlyUnwrappedOptional; } else { ImportTypeKind importKind = ImportTypeKind::Parameter; if (param->hasAttr()) diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index 6674ff059bcad..5e5fc64330657 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -152,13 +152,6 @@ enum class ImportTypeKind { /// This ensures that the parameter is not marked as Unmanaged. CFUnretainedOutParameter, - /// Import the type pointed to by a pointer or reference. - /// - /// This provides special treatment for pointer-to-ObjC-pointer - /// types, which get imported as pointers to *checked* optional, - /// *Pointer, instead of implicitly unwrapped optional as usual. - Pointee, - /// Import the type of an ObjC property. /// /// This enables the conversion of bridged types. Properties are always From 8eaeb51fe53fd4002e8b5ab6c2fd44f765273169 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 19 Sep 2019 22:02:33 -0700 Subject: [PATCH 125/199] [ConstraintSystem] Introduce a fix for assignment type mismatch Introduce a fix/diagnostic when there is a contextual mismatch between source and destination types of the assignment e.g.: ```swift var x: Int = 0 x = 4.0 // destination expects an `Int`, but source is a `Double` ``` --- lib/Sema/CSFix.cpp | 20 ++++++++ lib/Sema/CSFix.h | 17 +++++++ lib/Sema/CSSimplify.cpp | 46 +++++++++++++++---- test/Constraints/closures.swift | 2 +- test/Generics/deduction.swift | 2 +- .../Inputs/opaque-result-types-client.swift | 6 +-- 6 files changed, 79 insertions(+), 14 deletions(-) diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index 76b21b842dc1f..a8b1a60e1fd78 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -759,6 +759,26 @@ IgnoreContextualType *IgnoreContextualType::create(ConstraintSystem &cs, IgnoreContextualType(cs, resultTy, specifiedTy, locator); } +bool IgnoreAssignmentDestinationType::diagnose(Expr *root, bool asNote) const { + auto &cs = getConstraintSystem(); + auto *AE = cast(getAnchor()); + auto CTP = isa(AE->getDest()) ? CTP_SubscriptAssignSource + : CTP_AssignSource; + + ContextualFailure failure( + root, cs, CTP, getFromType(), getToType(), + cs.getConstraintLocator(AE->getSrc(), LocatorPathElt::ContextualType())); + return failure.diagnose(asNote); +} + +IgnoreAssignmentDestinationType * +IgnoreAssignmentDestinationType::create(ConstraintSystem &cs, Type sourceTy, + Type destTy, + ConstraintLocator *locator) { + return new (cs.getAllocator()) + IgnoreAssignmentDestinationType(cs, sourceTy, destTy, locator); +} + bool AllowInOutConversion::diagnose(Expr *root, bool asNote) const { auto &cs = getConstraintSystem(); InOutConversionFailure failure(root, cs, getFromType(), getToType(), diff --git a/lib/Sema/CSFix.h b/lib/Sema/CSFix.h index 3aadee4d3d00e..5e2350588147e 100644 --- a/lib/Sema/CSFix.h +++ b/lib/Sema/CSFix.h @@ -1299,6 +1299,23 @@ class IgnoreContextualType : public ContextualMismatch { ConstraintLocator *locator); }; +class IgnoreAssignmentDestinationType final : public ContextualMismatch { + IgnoreAssignmentDestinationType(ConstraintSystem &cs, Type sourceTy, + Type destTy, ConstraintLocator *locator) + : ContextualMismatch(cs, sourceTy, destTy, locator) {} + +public: + std::string getName() const override { + return "ignore type of the assignment destination"; + } + + bool diagnose(Expr *root, bool asNote = false) const override; + + static IgnoreAssignmentDestinationType *create(ConstraintSystem &cs, + Type sourceTy, Type destTy, + ConstraintLocator *locator); +}; + /// If this is an argument-to-parameter conversion which is associated with /// `inout` parameter, subtyping is not permitted, types have to /// be identical. diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 28c61599d823c..a4ac0b781d88d 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -2353,6 +2353,15 @@ bool ConstraintSystem::repairFailures( return false; }; + auto hasConversionOrRestriction = [&](ConversionRestrictionKind kind) { + return llvm::any_of(conversionsOrFixes, + [kind](const RestrictionOrFix correction) { + if (auto restriction = correction.getRestriction()) + return restriction == kind; + return false; + }); + }; + if (path.empty()) { if (!anchor) return false; @@ -2391,20 +2400,39 @@ bool ConstraintSystem::repairFailures( if (repairViaBridgingCast(*this, lhs, rhs, conversionsOrFixes, locator)) return true; + + // If we are trying to assign e.g. `Array` to `Array` let's + // give solver a chance to determine which generic parameters are + // mismatched and produce a fix for that. + if (hasConversionOrRestriction(ConversionRestrictionKind::DeepEquality)) + return false; + + // If the situation has to do with protocol composition types and + // destination doesn't have one of the conformances e.g. source is + // `X & Y` but destination is only `Y` or vice versa, there is a + // tailored "missing conformance" fix for that. + if (hasConversionOrRestriction(ConversionRestrictionKind::Existential)) + return false; + + // If this is an attempt to assign something to a value of optional type + // there is a possiblity that the problem is related to escapiness, so + // fix has to be delayed. + if (hasConversionOrRestriction( + ConversionRestrictionKind::ValueToOptional)) + return false; + + // If the destination of an assignment is l-value type + // it leaves only possible reason for failure - a type mismatch. + if (getType(AE->getDest())->is()) { + conversionsOrFixes.push_back(IgnoreAssignmentDestinationType::create( + *this, lhs, rhs, getConstraintLocator(locator))); + return true; + } } return false; } - auto hasConversionOrRestriction = [&](ConversionRestrictionKind kind) { - return llvm::any_of(conversionsOrFixes, - [kind](const RestrictionOrFix correction) { - if (auto restriction = correction.getRestriction()) - return restriction == kind; - return false; - }); - }; - auto elt = path.back(); switch (elt.getKind()) { case ConstraintLocator::LValueConversion: { diff --git a/test/Constraints/closures.swift b/test/Constraints/closures.swift index 0850eac442e7c..7680bab6e13c6 100644 --- a/test/Constraints/closures.swift +++ b/test/Constraints/closures.swift @@ -394,7 +394,7 @@ func rdar20868864(_ s: String) { func r22058555() { var firstChar: UInt8 = 0 "abc".withCString { chars in - firstChar = chars[0] // expected-error {{cannot assign value of type 'Int8' to type 'UInt8'}} + firstChar = chars[0] // expected-error {{cannot assign value of type 'Int8' to type 'UInt8'}} {{17-17=UInt8(}} {{25-25=)}} } } diff --git a/test/Generics/deduction.swift b/test/Generics/deduction.swift index ea7a3deb426ca..e10bf9fffaa8f 100644 --- a/test/Generics/deduction.swift +++ b/test/Generics/deduction.swift @@ -22,7 +22,7 @@ func useIdentity(_ x: Int, y: Float, i32: Int32) { // Deduction where the result type and input type can get different results var xx : X, yy : Y - xx = identity(yy) // expected-error{{cannot convert value of type 'Y' to expected argument type 'X'}} + xx = identity(yy) // expected-error{{cannot assign value of type 'Y' to type 'X'}} xx = identity2(yy) // expected-error{{cannot convert value of type 'Y' to expected argument type 'X'}} } diff --git a/test/ModuleInterface/Inputs/opaque-result-types-client.swift b/test/ModuleInterface/Inputs/opaque-result-types-client.swift index 4fb9870aa5d4c..88671bd7cc6c6 100644 --- a/test/ModuleInterface/Inputs/opaque-result-types-client.swift +++ b/test/ModuleInterface/Inputs/opaque-result-types-client.swift @@ -17,14 +17,14 @@ struct YourFoo: Foo {} func someTypeIsTheSame() { var a = foo(0) a = foo(0) - a = foo("") // expected-error{{cannot convert value of type 'String' to expected argument type 'Int'}} + a = foo("") // expected-error{{cannot assign value of type 'some Foo' (result of 'foo') to type 'some Foo' (result of 'foo')}} var b = foo("") - b = foo(0) // expected-error{{cannot convert value of type 'Int' to expected argument type 'String'}} + b = foo(0) // expected-error{{cannot assign value of type 'some Foo' (result of 'foo') to type 'some Foo' (result of 'foo')}} b = foo("") var c = foo(MyFoo()) - c = foo(0) // expected-error{{cannot convert value of type 'Int' to expected argument type 'MyFoo'}} + c = foo(0) // expected-error{{cannot assign value of type 'some Foo' (result of 'foo') to type 'some Foo' (result of 'foo')}} c = foo(MyFoo()) c = foo(YourFoo()) // expected-error{{cannot convert value of type 'YourFoo' to expected argument type 'MyFoo'}} From e90a68fa1733a30039564c0ca37115e4da339d76 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Thu, 19 Sep 2019 15:32:23 -0700 Subject: [PATCH 126/199] [polymorphic-builtins] Teach dataflow diagnostics how to emit an error if it sees an unspecialized polymorphic builtin. This will ensure that if an expert user is using this feature and makes a mistake as a result of tweaking their code, they get an error. This will ensure they do not ship and look into why this is happening. This is not intended to be used by anyone except for expert stdlib users. --- include/swift/AST/Builtins.h | 5 +- include/swift/AST/DiagnosticsSIL.def | 10 +++ include/swift/SIL/InstructionUtils.h | 26 +++++-- lib/AST/Builtins.cpp | 7 ++ lib/SIL/InstructionUtils.cpp | 6 ++ .../Mandatory/DataflowDiagnostics.cpp | 77 +++++++++++++++++-- .../polymorphic_builtins_diagnostics.sil | 29 +++++++ .../polymorphic_builtins_diagnostics.swift | 53 +++++++++++++ 8 files changed, 200 insertions(+), 13 deletions(-) create mode 100644 test/SILOptimizer/polymorphic_builtins_diagnostics.sil create mode 100644 test/SILOptimizer/polymorphic_builtins_diagnostics.swift diff --git a/include/swift/AST/Builtins.h b/include/swift/AST/Builtins.h index 71f276dddd8ca..e162d46247364 100644 --- a/include/swift/AST/Builtins.h +++ b/include/swift/AST/Builtins.h @@ -131,7 +131,10 @@ class IntrinsicInfo { /// Turn a string like "release" into the LLVM enum. llvm::AtomicOrdering decodeLLVMAtomicOrdering(StringRef O); - + +/// Returns true if the builtin with ID \p ID has a defined static overload for +/// the type \p Ty. +bool canBuiltinBeOverloadedForType(BuiltinValueKind ID, Type Ty); } #endif diff --git a/include/swift/AST/DiagnosticsSIL.def b/include/swift/AST/DiagnosticsSIL.def index bda7ff6739805..f1cc1ac27dff8 100644 --- a/include/swift/AST/DiagnosticsSIL.def +++ b/include/swift/AST/DiagnosticsSIL.def @@ -522,6 +522,16 @@ ERROR(oslog_property_not_constant, none, "'OSLogInterpolation.%0' is not a " ERROR(global_string_pointer_on_non_constant, none, "globalStringTablePointer " "builtin must used only on string literals", ()) +ERROR(polymorphic_builtin_passed_non_trivial_non_builtin_type, none, "Argument " + "of type %0 can not be passed as an argument to a Polymorphic " + "builtin. Polymorphic builtins can only be passed arguments that are " + "trivial builtin typed", (Type)) + +ERROR(polymorphic_builtin_passed_type_without_static_overload, none, "Static" + " overload %0 does not exist for polymorphic builtin '%1'. Static " + "overload implied by passing argument of type %2", + (Identifier, StringRef, Type)) + #ifndef DIAG_NO_UNDEF # if defined(DIAG) # undef DIAG diff --git a/include/swift/SIL/InstructionUtils.h b/include/swift/SIL/InstructionUtils.h index 2690d571881b8..23a5192c37d92 100644 --- a/include/swift/SIL/InstructionUtils.h +++ b/include/swift/SIL/InstructionUtils.h @@ -149,23 +149,37 @@ void findClosuresForFunctionValue(SILValue V, /// NOTE: If we perform this transformation, our builtin will no longer have any /// substitutions since we only substitute to concrete static overloads. struct PolymorphicBuiltinSpecializedOverloadInfo { + const BuiltinInfo *builtinInfo; Identifier staticOverloadIdentifier; SmallVector argTypes; SILType resultType; - bool hasOutParam = false; + bool hasOutParam; #ifndef NDEBUG private: - bool isInitialized = false; -#endif + bool isInitialized; public: - PolymorphicBuiltinSpecializedOverloadInfo() = default; +#endif - bool init(SILFunction *fn, BuiltinValueKind builtinKind, - ArrayRef oldOperandTypes, SILType oldResultType); + PolymorphicBuiltinSpecializedOverloadInfo() + : builtinInfo(nullptr), staticOverloadIdentifier(), argTypes(), + resultType(), hasOutParam(false), isInitialized(false) {} + /// Returns true if we were able to map the polymorphic builtin to a static + /// overload. False otherwise. + /// + /// NOTE: This does not mean that the static overload actually exists. bool init(BuiltinInst *bi); + + bool doesOverloadExist() const { + CanBuiltinType builtinType = argTypes.front().getAs(); + return canBuiltinBeOverloadedForType(builtinInfo->ID, builtinType); + } + +private: + bool init(SILFunction *fn, BuiltinValueKind builtinKind, + ArrayRef oldOperandTypes, SILType oldResultType); }; /// Given a polymorphic builtin \p bi, analyze its types and create a builtin diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index 99457c52d0c8e..b3fb42c5878a8 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -1256,6 +1256,13 @@ inline bool isBuiltinTypeOverloaded(Type T, OverloadedBuiltinKind OK) { llvm_unreachable("bad overloaded builtin kind"); } +bool swift::canBuiltinBeOverloadedForType(BuiltinValueKind ID, Type Ty) { + if (ID == BuiltinValueKind::None) + return false; + + return isBuiltinTypeOverloaded(Ty, OverloadedBuiltinKinds[unsigned(ID)]); +} + /// Table of string intrinsic names indexed by enum value. static const char *const IntrinsicNameTable[] = { "not_intrinsic", diff --git a/lib/SIL/InstructionUtils.cpp b/lib/SIL/InstructionUtils.cpp index a7155f6ba25cf..92d557ab85722 100644 --- a/lib/SIL/InstructionUtils.cpp +++ b/lib/SIL/InstructionUtils.cpp @@ -598,6 +598,12 @@ bool PolymorphicBuiltinSpecializedOverloadInfo::init( auto &ctx = fn->getASTContext(); staticOverloadIdentifier = ctx.getIdentifier(staticOverloadName); + + // Ok, we have our overload identifier. Grab the builtin info from the + // cache. If we did not actually found a valid builtin value kind for our + // overload, then we do not have a static overload for the passed in types, so + // return false. + builtinInfo = &fn->getModule().getBuiltinInfo(staticOverloadIdentifier); return true; } diff --git a/lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp b/lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp index 53572a64b6d0d..d459043eff3d8 100644 --- a/lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp +++ b/lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp @@ -10,21 +10,22 @@ // //===----------------------------------------------------------------------===// -#include "swift/SILOptimizer/PassManager/Passes.h" -#include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/ConstExpr.h" #include "swift/AST/ASTContext.h" #include "swift/AST/DiagnosticEngine.h" -#include "swift/AST/DiagnosticsSema.h" #include "swift/AST/DiagnosticsSIL.h" +#include "swift/AST/DiagnosticsSema.h" #include "swift/AST/Expr.h" #include "swift/AST/Stmt.h" +#include "swift/SIL/InstructionUtils.h" +#include "swift/SIL/SILConstants.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILLocation.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/SILVisitor.h" -#include "swift/SIL/SILConstants.h" +#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/ConstExpr.h" using namespace swift; @@ -175,6 +176,67 @@ static void diagnosePoundAssert(const SILInstruction *I, } } +static void diagnoseUnspecializedPolymorphicBuiltins(SILInstruction *inst) { + // We only validate if we are in a non-transparent function. + if (inst->getFunction()->isTransparent()) + return; + + auto *bi = dyn_cast(inst); + if (!bi) + return; + + auto kind = bi->getBuiltinKind(); + if (!kind) + return; + + if (!isPolymorphicBuiltin(*kind)) + return; + + const auto &builtinInfo = bi->getBuiltinInfo(); + + // First that the parameters were acceptable so we can emit a nice error to + // guide the user. + for (SILValue value : bi->getOperandValues()) { + SILType type = value->getType(); + SourceLoc loc; + if (auto *inst = value->getDefiningInstruction()) { + loc = inst->getLoc().getSourceLoc(); + } else { + loc = bi->getLoc().getSourceLoc(); + } + + if (!type.is() || !type.isTrivial(*bi->getFunction())) { + diagnose(bi->getModule().getASTContext(), loc, + diag::polymorphic_builtin_passed_non_trivial_non_builtin_type, + type.getASTType()); + return; + } + } + + // Ok, we have a valid type for a polymorphic builtin. Make sure we actually + // have a static overload for this type. + PolymorphicBuiltinSpecializedOverloadInfo overloadInfo; + bool ableToMapToStaticOverload = overloadInfo.init(bi); + (void)ableToMapToStaticOverload; + assert(ableToMapToStaticOverload); + if (!overloadInfo.doesOverloadExist()) { + diagnose(bi->getModule().getASTContext(), bi->getLoc().getSourceLoc(), + diag::polymorphic_builtin_passed_type_without_static_overload, + overloadInfo.staticOverloadIdentifier, + getBuiltinName(builtinInfo.ID), + overloadInfo.argTypes.front().getASTType()); + return; + } + + // Otherwise, something happen that we did not understand. This can only + // happen if we specialize the generic type in the builtin /after/ constant + // propagation runs at -Onone but before dataflow diagnostics. This is an + // error in implementation, so we assert. + llvm_unreachable("Found generic builtin with known static overload that it " + "could be transformed to. Did this builtin get its generic " + "type specialized /after/ constant propagation?"); +} + namespace { class EmitDFDiagnostics : public SILFunctionTransform { ~EmitDFDiagnostics() override {} @@ -186,11 +248,13 @@ class EmitDFDiagnostics : public SILFunctionTransform { return; SILModule &M = getFunction()->getModule(); - for (auto &BB : *getFunction()) + for (auto &BB : *getFunction()) { for (auto &I : BB) { diagnoseUnreachable(&I, M.getASTContext()); diagnoseStaticReports(&I, M); + diagnoseUnspecializedPolymorphicBuiltins(&I); } + } if (M.getASTContext().LangOpts.EnableExperimentalStaticAssert) { SymbolicValueBumpAllocator allocator; @@ -202,6 +266,7 @@ class EmitDFDiagnostics : public SILFunctionTransform { } } }; + } // end anonymous namespace diff --git a/test/SILOptimizer/polymorphic_builtins_diagnostics.sil b/test/SILOptimizer/polymorphic_builtins_diagnostics.sil new file mode 100644 index 0000000000000..3af92adaf7876 --- /dev/null +++ b/test/SILOptimizer/polymorphic_builtins_diagnostics.sil @@ -0,0 +1,29 @@ +// RUN: %target-sil-opt -module-name Swift -dataflow-diagnostics -verify %s + +sil_stage raw + +import Builtin + +struct MyInt { + var i : Builtin.Int32 +} + +sil @concrete_type_object_fail : $@convention(thin) (MyInt, MyInt) -> MyInt { +bb0(%0 : $MyInt, %1 : $MyInt): + %2 = builtin "generic_add"(%0 : $MyInt, %1 : $MyInt) : $MyInt // expected-error {{Argument of type 'MyInt' can not be passed as an argument to a Polymorphic builtin. Polymorphic builtins can only be passed arguments that are trivial builtin typed}} + return %2 : $MyInt +} + +sil @concrete_type_address_fail : $@convention(thin) (@in_guaranteed MyInt, @in_guaranteed MyInt) -> @out MyInt { +bb0(%0 : $*MyInt, %1 : $*MyInt, %2 : $*MyInt): + %3 = builtin "generic_add"(%0 : $*MyInt, %1 : $*MyInt, %2 : $*MyInt) : $() // expected-error {{Argument of type 'MyInt' can not be passed as an argument to a Polymorphic builtin. Polymorphic builtins can only be passed arguments that are trivial builtin typed}} + %9999 = tuple() + return %9999 : $() +} + +sil @concrete_type_address_fail_mismatched_trivial_type : $@convention(thin) (@in_guaranteed Builtin.FPIEEE32, @in_guaranteed Builtin.FPIEEE32) -> @out Builtin.FPIEEE32 { +bb0(%0 : $*Builtin.FPIEEE32, %1 : $*Builtin.FPIEEE32, %2 : $*Builtin.FPIEEE32): + %3 = builtin "generic_add"(%0 : $*Builtin.FPIEEE32, %1 : $*Builtin.FPIEEE32, %2 : $*Builtin.FPIEEE32) : $() // expected-error {{Static overload 'add_FPIEEE32' does not exist for polymorphic builtin 'generic_add'. Static overload implied by passing argument of type 'Builtin.FPIEEE32'}} + %9999 = tuple() + return %9999 : $() +} diff --git a/test/SILOptimizer/polymorphic_builtins_diagnostics.swift b/test/SILOptimizer/polymorphic_builtins_diagnostics.swift new file mode 100644 index 0000000000000..868432eb25182 --- /dev/null +++ b/test/SILOptimizer/polymorphic_builtins_diagnostics.swift @@ -0,0 +1,53 @@ +// RUN: %target-swift-frontend -parse-stdlib -emit-sil -verify %s + +import Swift + +struct MyInt { + var i: Builtin.Int64 +} + +@_transparent +func _isConcrete(type: T.Type) -> Bool { + return Bool(_builtinBooleanLiteral: Builtin.isConcrete(type)) +} + +func addVectorsNoDiagnostic(lhs: Builtin.Vec4xInt32, rhs: Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { + return Builtin.generic_add(lhs, rhs) +} + +func addVectorsEmitDiagnostic(lhs: MyInt, rhs: MyInt) -> MyInt { + return Builtin.generic_add(lhs, rhs) // expected-error {{Argument of type 'MyInt' can not be passed as an argument to a Polymorphic builtin. Polymorphic builtins can only be passed arguments that are trivial builtin typed}} +} + +func addVectorsGeneric(lhs: T, rhs: T) -> T { + return Builtin.generic_add(lhs, rhs) // expected-error {{Argument of type 'T' can not be passed as an argument to a Polymorphic builtin. Polymorphic builtins can only be passed arguments that are trivial builtin typed}} +} + +@_transparent +func calleeAddVectorsGenericTransparentGuarded(_ lhs: T, _ rhs: T) -> T { + // This will be eliminated during constant propagation ensuring that when we + // call in callerAddVectorsGenericTransparent, we do not get an error from our + // underlying call. + if _isConcrete(T.self) { + return Builtin.generic_add(lhs, rhs) + } + return lhs +} + +func callerAddVectorsGenericTransparent(_ lhs: Builtin.Vec4xInt32, _ rhs: Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { + // Since after transparent inlining, we have the correct type, we should get an error here.q + return calleeAddVectorsGenericTransparentGuarded(lhs, rhs) +} + +@_transparent +func calleeAddVectorsGenericTransparentUnguarded(_ lhs: T, _ rhs: T) -> T { + return Builtin.generic_add(lhs, rhs) +} + +func callerAddVectorsGenericTransparentUnguardedNoError(_ lhs: Builtin.Vec4xInt32, _ rhs: Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { + return calleeAddVectorsGenericTransparentUnguarded(lhs, rhs) +} + +func callerAddVectorsGenericTransparentUnguardedError(_ lhs: MyInt, _ rhs: MyInt) -> MyInt { + return calleeAddVectorsGenericTransparentUnguarded(lhs, rhs) // expected-error {{Argument of type 'MyInt' can not be passed as an argument to a Polymorphic builtin. Polymorphic builtins can only be passed arguments that are trivial builtin typed}} +} From 6c5185f2e3a63637b56cd9321da3b3c19dc5fc06 Mon Sep 17 00:00:00 2001 From: Owen Voorhees Date: Wed, 17 Jul 2019 18:04:20 -0700 Subject: [PATCH 127/199] Improve diagnostic when attempting to pass an Array to a variadic argument - Give a more specific diagnostic which indicates the parameter is variadic - If the argument is an Array literal, offer to drop the brackets --- include/swift/AST/DiagnosticsSema.def | 9 +++++ lib/Sema/CSApply.cpp | 17 ++++---- lib/Sema/CSDiag.cpp | 15 ++++--- lib/Sema/CSDiagnostics.cpp | 49 +++++++++++++++++++++-- lib/Sema/CSDiagnostics.h | 21 ++++++++++ lib/Sema/CSFix.cpp | 30 ++++++++++++++ lib/Sema/CSFix.h | 22 +++++++++++ lib/Sema/CSSimplify.cpp | 10 ++++- lib/Sema/ConstraintLocator.h | 29 +++++++++++--- test/Constraints/diagnostics.swift | 56 +++++++++++++++++++++++++++ 10 files changed, 235 insertions(+), 23 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 15e1b8143253d..9608445b443f7 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -384,6 +384,15 @@ NOTE(candidate_has_invalid_argument_at_position,none, "candidate expects value of type %0 at position #%1", (Type, unsigned)) +ERROR(cannot_convert_array_to_variadic,none, + "cannot pass array of type %0 as variadic arguments of type %1", + (Type,Type)) +NOTE(candidate_would_match_array_to_variadic,none, + "candidate would match if array elements were passed as" + " variadic arguments of type %0", (Type)) +NOTE(suggest_pass_elements_directly,none, + "remove brackets to pass array elements directly", ()) + ERROR(cannot_convert_argument_value_generic,none, "cannot convert value of type %0 (%1) to expected argument type %2 (%3)", (Type, StringRef, Type, StringRef)) diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 1a11940931db0..7c4afae6d4f19 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -5384,10 +5384,11 @@ Expr *ExprRewriter::coerceCallArguments( auto params = funcType->getParams(); // Local function to produce a locator to refer to the given parameter. - auto getArgLocator = [&](unsigned argIdx, unsigned paramIdx) - -> ConstraintLocatorBuilder { + auto getArgLocator = + [&](unsigned argIdx, unsigned paramIdx, + ParameterTypeFlags flags) -> ConstraintLocatorBuilder { return locator.withPathElement( - LocatorPathElt::ApplyArgToParam(argIdx, paramIdx)); + LocatorPathElt::ApplyArgToParam(argIdx, paramIdx, flags)); }; bool matchCanFail = @@ -5499,8 +5500,9 @@ Expr *ExprRewriter::coerceCallArguments( } // Convert the argument. - auto convertedArg = coerceToType(arg, param.getPlainType(), - getArgLocator(argIdx, paramIdx)); + auto convertedArg = coerceToType( + arg, param.getPlainType(), + getArgLocator(argIdx, paramIdx, param.getParameterFlags())); if (!convertedArg) return nullptr; @@ -5620,8 +5622,9 @@ Expr *ExprRewriter::coerceCallArguments( convertedArg = cs.TC.buildAutoClosureExpr(dc, arg, closureType); cs.cacheExprTypes(convertedArg); } else { - convertedArg = - coerceToType(arg, paramType, getArgLocator(argIdx, paramIdx)); + convertedArg = coerceToType( + arg, paramType, + getArgLocator(argIdx, paramIdx, param.getParameterFlags())); } if (!convertedArg) diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp index bf483ab26de16..793d9b6c30dbe 100644 --- a/lib/Sema/CSDiag.cpp +++ b/lib/Sema/CSDiag.cpp @@ -3461,11 +3461,16 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) { // case (let (_, _, _)) + 1: break // } if (callExpr->isImplicit() && overloadName == "~=") { - auto *locator = - CS.getConstraintLocator(callExpr, - {ConstraintLocator::ApplyArgument, - LocatorPathElt::ApplyArgToParam(0, 0)}, - /*summaryFlags=*/0); + auto flags = ParameterTypeFlags(); + if (calleeInfo.candidates.size() == 1) + if (auto fnType = calleeInfo.candidates[0].getFunctionType()) + flags = fnType->getParams()[0].getParameterFlags(); + + auto *locator = CS.getConstraintLocator( + callExpr, + {ConstraintLocator::ApplyArgument, + LocatorPathElt::ApplyArgToParam(0, 0, flags)}, + /*summaryFlags=*/0); ArgumentMismatchFailure failure(expr, CS, lhsType, rhsType, locator); return failure.diagnosePatternMatchingMismatch(); diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 21612431b3604..6f757b52f650d 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -4611,9 +4611,11 @@ bool ArgumentMismatchFailure::diagnoseUseOfReferenceEqualityOperator() const { // one would cover both arguments. if (getAnchor() == rhs && rhsType->is()) { auto &cs = getConstraintSystem(); - if (cs.hasFixFor(cs.getConstraintLocator( - binaryOp, {ConstraintLocator::ApplyArgument, - LocatorPathElt::ApplyArgToParam(0, 0)}))) + auto info = getFunctionArgApplyInfo(locator); + if (info && cs.hasFixFor(cs.getConstraintLocator( + binaryOp, {ConstraintLocator::ApplyArgument, + LocatorPathElt::ApplyArgToParam( + 0, 0, info->getParameterFlagsAtIndex(0))}))) return true; } @@ -4763,3 +4765,44 @@ bool ArgumentMismatchFailure::diagnoseArchetypeMismatch() const { return true; } + +void ExpandArrayIntoVarargsFailure::tryDropArrayBracketsFixIt( + Expr *anchor) const { + // If this is an array literal, offer to remove the brackets and pass the + // elements directly as variadic arguments. + if (auto *arrayExpr = dyn_cast(anchor)) { + auto diag = emitDiagnostic(arrayExpr->getLoc(), + diag::suggest_pass_elements_directly); + diag.fixItRemove(arrayExpr->getLBracketLoc()) + .fixItRemove(arrayExpr->getRBracketLoc()); + // Handle the case where the array literal has a trailing comma. + if (arrayExpr->getNumCommas() == arrayExpr->getNumElements()) + diag.fixItRemove(arrayExpr->getCommaLocs().back()); + } +} + +bool ExpandArrayIntoVarargsFailure::diagnoseAsError() { + if (auto anchor = getAnchor()) { + emitDiagnostic(anchor->getLoc(), diag::cannot_convert_array_to_variadic, + getFromType(), getToType()); + tryDropArrayBracketsFixIt(anchor); + // TODO: Array splat fix-it once that's supported. + return true; + } + return false; +} + +bool ExpandArrayIntoVarargsFailure::diagnoseAsNote() { + auto overload = getChoiceFor(getLocator()); + auto anchor = getAnchor(); + if (!overload || !anchor) + return false; + + if (auto chosenDecl = overload->choice.getDeclOrNull()) { + emitDiagnostic(chosenDecl, diag::candidate_would_match_array_to_variadic, + getToType()); + tryDropArrayBracketsFixIt(anchor); + return true; + } + return false; +} diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 977981773da45..cc3c07ff20029 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -1582,8 +1582,25 @@ class InvalidTupleSplatWithSingleParameterFailure final Type paramTy, ConstraintLocator *locator) : FailureDiagnostic(root, cs, locator), ParamType(paramTy) {} + bool diagnoseAsError() override; +}; + +/// Diagnose situation when an array is passed instead of varargs. +/// +/// ```swift +/// func foo(_ x: Int...) {} +/// foo([1,2,3]]) // foo expects varags like foo(1,2,3) instead. +/// ``` +class ExpandArrayIntoVarargsFailure final : public ContextualFailure { +public: + ExpandArrayIntoVarargsFailure(Expr *root, ConstraintSystem &cs, Type lhs, + Type rhs, ConstraintLocator *locator) + : ContextualFailure(root, cs, lhs, rhs, locator) {} bool diagnoseAsError() override; + bool diagnoseAsNote() override; + + void tryDropArrayBracketsFixIt(Expr *anchor) const; }; /// Diagnose a situation there is a mismatch between argument and parameter @@ -1715,6 +1732,10 @@ class FunctionArgApplyInfo { ParameterTypeFlags getParameterFlags() const { return FnType->getParams()[ParamIdx].getParameterFlags(); } + + ParameterTypeFlags getParameterFlagsAtIndex(unsigned idx) const { + return FnType->getParams()[idx].getParameterFlags(); + } }; } // end namespace constraints diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index 76b21b842dc1f..2a59f0a33b844 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -795,6 +795,36 @@ static bool isValueOfRawRepresentable(ConstraintSystem &cs, return false; } +ExpandArrayIntoVarargs * +ExpandArrayIntoVarargs::attempt(ConstraintSystem &cs, Type argType, + Type paramType, + ConstraintLocatorBuilder locator) { + auto constraintLocator = cs.getConstraintLocator(locator); + auto elementType = cs.isArrayType(argType); + if (elementType && + constraintLocator->getLastElementAs() + ->getParameterFlags() + .isVariadic()) { + auto options = ConstraintSystem::TypeMatchOptions( + ConstraintSystem::TypeMatchFlags::TMF_ApplyingFix | + ConstraintSystem::TypeMatchFlags::TMF_GenerateConstraints); + auto result = + cs.matchTypes(*elementType, paramType, + ConstraintKind::ArgumentConversion, options, locator); + if (result.isSuccess()) + return new (cs.getAllocator()) + ExpandArrayIntoVarargs(cs, argType, paramType, constraintLocator); + } + + return nullptr; +} + +bool ExpandArrayIntoVarargs::diagnose(Expr *root, bool asNote) const { + ExpandArrayIntoVarargsFailure failure( + root, getConstraintSystem(), getFromType(), getToType(), getLocator()); + return failure.diagnose(asNote); +} + ExplicitlyConstructRawRepresentable * ExplicitlyConstructRawRepresentable::attempt(ConstraintSystem &cs, Type argType, Type paramType, diff --git a/lib/Sema/CSFix.h b/lib/Sema/CSFix.h index 3aadee4d3d00e..5b9226e0fa18e 100644 --- a/lib/Sema/CSFix.h +++ b/lib/Sema/CSFix.h @@ -204,6 +204,9 @@ enum class FixKind : uint8_t { /// Use raw value type associated with raw representative accessible /// using `.rawValue` member. UseValueTypeOfRawRepresentative, + /// If an array was passed to a variadic argument, give a specific diagnostic + /// and offer to drop the brackets if it's a literal. + ExpandArrayIntoVarargs, }; class ConstraintFix { @@ -1342,6 +1345,25 @@ class AllowArgumentMismatch : public ContextualMismatch { ConstraintLocator *locator); }; +class ExpandArrayIntoVarargs final : public AllowArgumentMismatch { + + ExpandArrayIntoVarargs(ConstraintSystem &cs, Type argType, Type paramType, + ConstraintLocator *locator) + : AllowArgumentMismatch(cs, FixKind::ExpandArrayIntoVarargs, argType, + paramType, locator) {} + +public: + std::string getName() const override { + return "cannot pass Array elements as variadic arguments"; + } + + bool diagnose(Expr *root, bool asNote = false) const override; + + static ExpandArrayIntoVarargs *attempt(ConstraintSystem &cs, Type argType, + Type paramType, + ConstraintLocatorBuilder locator); +}; + class ExplicitlyConstructRawRepresentable final : public AllowArgumentMismatch { ExplicitlyConstructRawRepresentable(ConstraintSystem &cs, Type argType, Type paramType, diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 28c61599d823c..8e2db4ff62f40 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -913,8 +913,8 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments( // Compare each of the bound arguments for this parameter. for (auto argIdx : parameterBindings[paramIdx]) { - auto loc = locator.withPathElement( - LocatorPathElt::ApplyArgToParam(argIdx, paramIdx)); + auto loc = locator.withPathElement(LocatorPathElt::ApplyArgToParam( + argIdx, paramIdx, param.getParameterFlags())); auto argTy = argsWithLabels[argIdx].getOldType(); bool matchingAutoClosureResult = param.isAutoClosure(); @@ -2598,6 +2598,11 @@ bool ConstraintSystem::repairFailures( elt.castTo().getParamIdx() == 1) break; + if (auto *fix = ExpandArrayIntoVarargs::attempt(*this, lhs, rhs, locator)) { + conversionsOrFixes.push_back(fix); + break; + } + if (auto *fix = ExplicitlyConstructRawRepresentable::attempt( *this, lhs, rhs, locator)) { conversionsOrFixes.push_back(fix); @@ -7610,6 +7615,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint( case FixKind::SkipUnhandledConstructInFunctionBuilder: case FixKind::UsePropertyWrapper: case FixKind::UseWrappedValue: + case FixKind::ExpandArrayIntoVarargs: case FixKind::UseValueTypeOfRawRepresentative: case FixKind::ExplicitlyConstructRawRepresentable: { return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved; diff --git a/lib/Sema/ConstraintLocator.h b/lib/Sema/ConstraintLocator.h index 34619cf370f26..663312bb27414 100644 --- a/lib/Sema/ConstraintLocator.h +++ b/lib/Sema/ConstraintLocator.h @@ -184,8 +184,10 @@ class ConstraintLocator : public llvm::FoldingSetNode { case TypeParameterRequirement: case ConditionalRequirement: - case ApplyArgToParam: return 2; + + case ApplyArgToParam: + return 3; } llvm_unreachable("Unhandled PathElementKind in switch."); @@ -282,12 +284,12 @@ class ConstraintLocator : public llvm::FoldingSetNode { uint64_t storedKind : 3; /// Encode a path element kind and a value into the storage format. - static uint64_t encodeStorage(PathElementKind kind, unsigned value) { - return ((uint64_t)value << 8) | kind; + static uint64_t encodeStorage(PathElementKind kind, uint64_t value) { + return (value << 8) | kind; } /// Decode a storage value into path element kind and value. - static std::pair + static std::pair decodeStorage(uint64_t storage) { return { (PathElementKind)((unsigned)storage & 0xFF), storage >> 8 }; } @@ -323,6 +325,17 @@ class ConstraintLocator : public llvm::FoldingSetNode { assert(value1 == getValue(1) && "value1 truncated"); } + PathElement(PathElementKind kind, uint64_t value0, uint64_t value1, + uint64_t value2) + : storage(encodeStorage(kind, value0 << 32 | value1 << 16 | value2)), + storedKind(StoredKindAndValue) { + assert(numNumericValuesInPathElement(kind) == 3 && + "Path element kind does not require 3 values"); + assert(value0 == getValue(0) && "value0 truncated"); + assert(value1 == getValue(1) && "value1 truncated"); + assert(value2 == getValue(2) && "value2 truncated"); + } + /// Store a path element with an associated pointer, accessible using /// \c getStoredPointer. template @@ -695,11 +708,15 @@ dyn_cast(const LocatorPathElt &) = delete; // Use LocatorPathElt::getAs instead. class LocatorPathElt::ApplyArgToParam final : public LocatorPathElt { public: - ApplyArgToParam(unsigned argIdx, unsigned paramIdx) - : LocatorPathElt(ConstraintLocator::ApplyArgToParam, argIdx, paramIdx) {} + ApplyArgToParam(unsigned argIdx, unsigned paramIdx, ParameterTypeFlags flags) + : LocatorPathElt(ConstraintLocator::ApplyArgToParam, argIdx, paramIdx, + flags.toRaw()) {} unsigned getArgIdx() const { return getValue(0); } unsigned getParamIdx() const { return getValue(1); } + ParameterTypeFlags getParameterFlags() const { + return ParameterTypeFlags::fromRaw(getValue(2)); + } static bool classof(const LocatorPathElt *elt) { return elt->getKind() == ConstraintLocator::ApplyArgToParam; diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index bc76267222193..b672c88180b82 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -299,6 +299,62 @@ func rdar21784170() { (Array.init as (Double...) -> Array)(initial as (Double, Double)) // expected-error {{cannot convert value of type '(Double, Double)' to expected argument type 'Double'}} } +// Diagnose passing an array in lieu of variadic parameters +func variadic(_ x: Int...) {} +func variadicArrays(_ x: [Int]...) {} +func variadicAny(_ x: Any...) {} +struct HasVariadicSubscript { + subscript(_ x: Int...) -> Int { + get { 0 } + } +} +let foo = HasVariadicSubscript() + +let array = [1,2,3] +let arrayWithOtherEltType = ["hello", "world"] + +variadic(array) // expected-error {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} +variadic([1,2,3]) // expected-error {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} +// expected-note@-1 {{remove brackets to pass array elements directly}} {{10-11=}} {{16-17=}} +variadic([1,2,3,]) // expected-error {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} +// expected-note@-1 {{remove brackets to pass array elements directly}} {{10-11=}} {{16-17=}} {{17-18=}} +variadic(0, array, 4) // expected-error {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} +variadic(0, [1,2,3], 4) // expected-error {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} +// expected-note@-1 {{remove brackets to pass array elements directly}} {{13-14=}} {{19-20=}} +variadic(0, [1,2,3,], 4) // expected-error {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} +// expected-note@-1 {{remove brackets to pass array elements directly}} {{13-14=}} {{19-20=}} {{20-21=}} +variadic(arrayWithOtherEltType) // expected-error {{cannot convert value of type '[String]' to expected argument type 'Int'}} +variadic(1, arrayWithOtherEltType) // expected-error {{cannot convert value of type '[String]' to expected argument type 'Int'}} + +// FIXME: SR-11104 +variadic(["hello", "world"]) // expected-error 2 {{cannot convert value of type 'String' to expected element type 'Int'}} +// expected-error@-1 {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} +// expected-note@-2 {{remove brackets to pass array elements directly}} + +variadic([1] + [2] as [Int]) // expected-error {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} + +foo[array] // expected-error {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} +foo[[1,2,3]] // expected-error {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} +// expected-note@-1 {{remove brackets to pass array elements directly}} {{5-6=}} {{11-12=}} +foo[0, [1,2,3], 4] // expected-error {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} +// expected-note@-1 {{remove brackets to pass array elements directly}} {{8-9=}} {{14-15=}} + +variadicAny(array) +variadicAny([1,2,3]) +variadicArrays(array) +variadicArrays([1,2,3]) +variadicArrays(arrayWithOtherEltType) // expected-error {{cannot convert value of type '[String]' to expected argument type '[Int]'}} +// expected-note@-1 {{arguments to generic parameter 'Element' ('String' and 'Int') are expected to be equal}} +variadicArrays(1,2,3) // expected-error 3 {{cannot convert value of type 'Int' to expected argument type '[Int]'}} + +protocol Proto {} +func f(x: [T]) {} +func f(x: Int...) {} +f(x: [1,2,3]) +// TODO(diagnostics): Diagnose both the missing conformance and the disallowed array splat to cover both overloads. +// expected-error@-2 {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} +// expected-note@-3 {{remove brackets to pass array elements directly}} + // BOGUS: unexpected trailing closure func expect(_: T) -> (U.Type) -> Int { return { a in 0 } } func expect(_: T, _: Int = 1) -> (U.Type) -> String { return { a in "String" } } From 64ed0a40773faf6d6cc6c1ca1ffc715a574d400f Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Fri, 20 Sep 2019 17:34:17 -0700 Subject: [PATCH 128/199] stdlib: silence a unused function warning (NFC) Pre-process away the unused function on Darwin. NFC. --- stdlib/public/stubs/ThreadLocalStorage.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/stdlib/public/stubs/ThreadLocalStorage.cpp b/stdlib/public/stubs/ThreadLocalStorage.cpp index 7a51daaf0da56..50168f955bc6c 100644 --- a/stdlib/public/stubs/ThreadLocalStorage.cpp +++ b/stdlib/public/stubs/ThreadLocalStorage.cpp @@ -23,6 +23,8 @@ void _stdlib_destroyTLS(void *); SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API void *_stdlib_createTLS(void); +#if !SWIFT_TLS_HAS_RESERVED_PTHREAD_SPECIFIC || (defined(_WIN32) && !defined(__CYGWIN__)) + static void #if defined(_M_IX86) __stdcall @@ -31,6 +33,8 @@ destroyTLS_CCAdjustmentThunk(void *ptr) { _stdlib_destroyTLS(ptr); } +#endif + #if defined(_WIN32) && !defined(__CYGWIN__) typedef From e89efa8f8152cf1875b9031dbb63381678597a26 Mon Sep 17 00:00:00 2001 From: Nathan Hawes Date: Fri, 20 Sep 2019 18:46:53 -0700 Subject: [PATCH 129/199] [parser] Fix tuple type round-tripping issue `public init(a: (b || c))` became `public init(a: )(b || c)` after round-tripping. Resolves rdar://problem/55280477 --- include/swift/Parse/Parser.h | 5 +++-- lib/Parse/ParseType.cpp | 13 ++++++++---- lib/Parse/Parser.cpp | 21 +++++++++++++------ .../round_trip_invalid.swift.withkinds | 3 ++- test/Syntax/round_trip_invalid.swift | 1 + 5 files changed, 30 insertions(+), 13 deletions(-) diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 91ee72590704c..840b0dac37ed1 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -876,7 +876,7 @@ class Parser { /// /// If the input is malformed, this emits the specified error diagnostic. bool parseToken(tok K, SourceLoc &TokLoc, const Diagnostic &D); - llvm::Optional parseTokenSyntax(tok K, + llvm::Optional parseTokenSyntax(tok K, SourceLoc &TokLoc, const Diagnostic &D); template @@ -896,7 +896,8 @@ class Parser { SourceLoc OtherLoc); llvm::Optional - parseMatchingTokenSyntax(tok K, Diag<> ErrorDiag, SourceLoc OtherLoc); + parseMatchingTokenSyntax(tok K, SourceLoc &TokLoc, Diag<> ErrorDiag, + SourceLoc OtherLoc); /// Returns the proper location for a missing right brace, parenthesis, etc. SourceLoc getLocForMissingMatchingToken() const; diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index f6542b3da80b1..78ff1dad049d6 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -109,7 +109,8 @@ Parser::parseLayoutConstraintSyntax() { if (Tok.is(tok::r_paren)) builder.useRightParen(consumeTokenSyntax(tok::r_paren)); } else { - auto rParen = parseMatchingTokenSyntax(tok::r_paren, + SourceLoc rParenLoc; + auto rParen = parseMatchingTokenSyntax(tok::r_paren, rParenLoc, diag::expected_rparen_layout_constraint, lParenLoc); if (rParen) @@ -1166,6 +1167,8 @@ Parser::TypeResult Parser::parseTypeTupleBody() { }); if (!Status.isSuccess()) { + if (RParen) + Junk.push_back(std::move(*RParen)); auto ty = ParsedSyntaxRecorder::makeUnknownType(Junk, *SyntaxContext); return makeParsedResult(std::move(ty), Status); } @@ -1253,9 +1256,9 @@ Parser::TypeResult Parser::parseTypeArray(ParsedTypeSyntax Base, // Ignore integer literal between '[' and ']' ignoreIf(tok::integer_literal); - auto RSquareLoc = Tok.getLoc(); + SourceLoc RSquareLoc; auto RSquare = parseMatchingTokenSyntax( - tok::r_square, diag::expected_rbracket_array_type, LSquareLoc); + tok::r_square, RSquareLoc, diag::expected_rbracket_array_type, LSquareLoc); if (RSquare) { // If we parsed something valid, diagnose it with a fixit to rewrite it to @@ -1301,7 +1304,9 @@ Parser::TypeResult Parser::parseTypeCollection() { auto Diag = Colon ? diag::expected_rbracket_dictionary_type : diag::expected_rbracket_array_type; - auto RSquare = parseMatchingTokenSyntax(tok::r_square, Diag, LSquareLoc); + SourceLoc RSquareLoc; + auto RSquare = parseMatchingTokenSyntax(tok::r_square, RSquareLoc, Diag, + LSquareLoc); if (!RSquare) Status.setIsParseError(); diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 7980fd39f1006..ea85b9ee8a4ad 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -1242,8 +1242,10 @@ bool Parser::parseMatchingToken(tok K, SourceLoc &TokLoc, Diag<> ErrorDiag, return false; } -Optional Parser::parseTokenSyntax(tok K, const Diagnostic &D) { +Optional Parser::parseTokenSyntax(tok K, SourceLoc &TokLoc, + const Diagnostic &D) { if (Tok.is(K)) { + TokLoc = Tok.getLoc(); return consumeTokenSyntax(); } @@ -1253,7 +1255,7 @@ Optional Parser::parseTokenSyntax(tok K, const Diagnostic &D) } Optional -Parser::parseMatchingTokenSyntax(tok K, Diag<> ErrorDiag, SourceLoc OtherLoc) { +Parser::parseMatchingTokenSyntax(tok K, SourceLoc &TokLoc, Diag<> ErrorDiag, SourceLoc OtherLoc) { Diag<> OtherNote; switch (K) { case tok::r_paren: OtherNote = diag::opening_paren; break; @@ -1262,9 +1264,11 @@ Parser::parseMatchingTokenSyntax(tok K, Diag<> ErrorDiag, SourceLoc OtherLoc) { default: llvm_unreachable("unknown matching token!"); } - auto Token = parseTokenSyntax(K, ErrorDiag); - if (!Token) + auto Token = parseTokenSyntax(K, TokLoc, ErrorDiag); + if (!Token) { + TokLoc = getLocForMissingMatchingToken(); diagnose(OtherLoc, OtherNote); + } return Token; } @@ -1391,9 +1395,14 @@ Parser::parseListSyntax(tok RightK, SourceLoc LeftLoc, if (Status.isError()) { // If we've already got errors, don't emit missing RightK diagnostics. - RightLoc = Tok.is(RightK) ? consumeToken() : PreviousLoc; + if (Tok.is(RightK)) { + RightLoc = Tok.getLoc(); + Right = consumeTokenSyntax(RightK); + } else { + RightLoc = getLocForMissingMatchingToken(); + } } else { - Right = parseMatchingTokenSyntax(RightK, ErrorDiag, LeftLoc); + Right = parseMatchingTokenSyntax(RightK, RightLoc, ErrorDiag, LeftLoc); if (!Right) Status.setIsParseError(); } diff --git a/test/Syntax/Outputs/round_trip_invalid.swift.withkinds b/test/Syntax/Outputs/round_trip_invalid.swift.withkinds index ad6518bb11185..20da5f46d975c 100644 --- a/test/Syntax/Outputs/round_trip_invalid.swift.withkinds +++ b/test/Syntax/Outputs/round_trip_invalid.swift.withkinds @@ -19,4 +19,5 @@ class C { struct S { enum E { protocol P { -extension P { +extension P { +public init(a: (Int || String)) diff --git a/test/Syntax/round_trip_invalid.swift b/test/Syntax/round_trip_invalid.swift index 9cc7750288de3..49817bd8e5261 100644 --- a/test/Syntax/round_trip_invalid.swift +++ b/test/Syntax/round_trip_invalid.swift @@ -20,3 +20,4 @@ struct S { enum E { protocol P { extension P { +public init(a: (Int || String)) From 2df956a4cad5bc86f468a482daa76c26cb3d5e48 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 20 Sep 2019 13:58:00 -0700 Subject: [PATCH 130/199] Make decl shadowing ask the right question If it's going to validate the declaration, it wants to know if there's an interface type. Computing the generic signature can be done on demand. --- lib/AST/NameLookup.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index 5477e66249aec..71d44ca8d1c40 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -470,7 +470,7 @@ static void recordShadowedDecls(ArrayRef decls, // If the decl is currently being validated, this is likely a recursive // reference and we'll want to skip ahead so as to avoid having its type // attempt to desugar itself. - if (!decl->hasValidSignature()) + if (!decl->hasInterfaceType()) continue; // FIXME: the canonical type makes a poor signature, because we don't From 321d9b76e7922fd0397cec2bc10e018b7d2cd385 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 20 Sep 2019 13:58:28 -0700 Subject: [PATCH 131/199] Remove a dead cycle check --- lib/Sema/ConstraintSystem.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index dba3cbd3572a4..de3064005e9d0 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -498,16 +498,6 @@ Type ConstraintSystem::openUnboundGenericType(UnboundGenericType *unbound, ConstraintLocatorBuilder locator, OpenedTypeMap &replacements) { auto unboundDecl = unbound->getDecl(); - - // If the unbound decl hasn't been validated yet, we have a circular - // dependency that isn't being diagnosed properly. - // - // FIXME: Delete this condition. He's dead Jim. - if (!unboundDecl->hasComputedGenericSignature()) { - TC.diagnose(unboundDecl, diag::circular_reference); - return Type(); - } - auto parentTy = unbound->getParent(); if (parentTy) { parentTy = openUnboundGenericType(parentTy, locator); From e7fccde40c7840962e5c0329bf83eaaca56be843 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 20 Sep 2019 14:01:13 -0700 Subject: [PATCH 132/199] Directly detect the cyclic case while computing conditional requirement The general class of cycle here is when validation asks for the generic signature which triggers requirement checking which forces us to ask for the generic signature of the extension again. We should look into a more principled solution. See rdar://55263708 --- include/swift/AST/Decl.h | 1 + lib/AST/Decl.cpp | 5 +++++ lib/AST/ProtocolConformance.cpp | 34 ++++++++++++++------------------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index ead57c4b23ad4..5bb8cff18ab2b 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -1536,6 +1536,7 @@ class GenericContext : private _GenericContext, public DeclContext { /// \endcode bool isGeneric() const { return getGenericParams() != nullptr; } bool hasComputedGenericSignature() const; + bool isComputingGenericSignature() const; /// Retrieve the trailing where clause for this extension, if any. TrailingWhereClause *getTrailingWhereClause() const { diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 2ae0f8742ac18..91dda4c2edc2d 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -859,6 +859,11 @@ GenericParamList *GenericContext::getGenericParams() const { bool GenericContext::hasComputedGenericSignature() const { return GenericSigAndBit.getInt(); } + +bool GenericContext::isComputingGenericSignature() const { + return getASTContext().evaluator.hasActiveRequest( + GenericSignatureRequest{const_cast(this)}); +} GenericSignature *GenericContext::getGenericSignature() const { return evaluateOrDefault( diff --git a/lib/AST/ProtocolConformance.cpp b/lib/AST/ProtocolConformance.cpp index d26e50009a855..da5a61d94ba86 100644 --- a/lib/AST/ProtocolConformance.cpp +++ b/lib/AST/ProtocolConformance.cpp @@ -531,7 +531,7 @@ void NormalProtocolConformance::differenceAndStoreConditionalRequirements() assert(CRState == ConditionalRequirementsState::Computing); CRState = ConditionalRequirementsState::Uncomputed; }; - + auto &ctxt = getProtocol()->getASTContext(); auto DC = getDeclContext(); // A non-extension conformance won't have conditional requirements. @@ -550,30 +550,24 @@ void NormalProtocolConformance::differenceAndStoreConditionalRequirements() return; } - // The type is generic, but the extension doesn't have a signature yet, so - // we might be in a recursive validation situation. - if (!ext->hasComputedGenericSignature()) { - // If the extension is invalid, it won't ever get a signature, so we - // "succeed" with an empty result instead. - if (ext->isInvalid()) { - success({}); - return; - } + // If the extension is invalid, it won't ever get a signature, so we + // "succeed" with an empty result instead. + if (ext->isInvalid()) { + success({}); + return; + } - // Otherwise we'll try again later. + // Recursively validating the signature comes up frequently as expanding + // conformance requirements might re-enter this method. We can at least catch + // this and come back to these requirements later. + // + // FIXME: In the long run, break this cycle in a more principled way. + if (ext->isComputingGenericSignature()) { failure(); return; } - - // FIXME: All of this will be removed when validateExtension goes away. - auto extensionSig = ext->getGenericSignature(); - if (!extensionSig) { - if (auto lazyResolver = ctxt.getLazyResolver()) { - lazyResolver->resolveExtension(ext); - extensionSig = ext->getGenericSignature(); - } - } + auto extensionSig = ext->getGenericSignature(); auto canExtensionSig = extensionSig->getCanonicalSignature(); auto canTypeSig = typeSig->getCanonicalSignature(); if (canTypeSig == canExtensionSig) { From f968f4282d53f487b29cf456415df46f9adf8748 Mon Sep 17 00:00:00 2001 From: David Zarzycki Date: Sat, 21 Sep 2019 08:15:11 +0300 Subject: [PATCH 133/199] [Testing] Workaroud glibc non-null attributes --- test/stdlib/POSIX.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/stdlib/POSIX.swift b/test/stdlib/POSIX.swift index 91cec1c2e01bd..ead9a623554b4 100644 --- a/test/stdlib/POSIX.swift +++ b/test/stdlib/POSIX.swift @@ -69,7 +69,7 @@ POSIXTests.test("sem_open success") { let sem = sem_open(semaphoreName, O_CREAT, 0o777, 1) expectNotEqual(SEM_FAILED, sem) - let res = sem_close(sem) + let res = sem_close(sem!) expectEqual(0, res) let res2 = sem_unlink(semaphoreName) @@ -83,7 +83,7 @@ POSIXTests.test("sem_open O_EXCL success") { let sem = sem_open(semaphoreName, O_CREAT | O_EXCL, 0o777, 1) expectNotEqual(SEM_FAILED, sem) - let res = sem_close(sem) + let res = sem_close(sem!) expectEqual(0, res) let res2 = sem_unlink(semaphoreName) @@ -102,7 +102,7 @@ POSIXTests.test("sem_open existing") { // difficult. expectNotEqual(SEM_FAILED, sem2) - let res = sem_close(sem) + let res = sem_close(sem!) expectEqual(0, res) let res2 = sem_unlink(semaphoreName) @@ -120,7 +120,7 @@ POSIXTests.test("sem_open existing O_EXCL fail") { expectEqual(SEM_FAILED, sem2) expectEqual(EEXIST, errno) - let res = sem_close(sem) + let res = sem_close(sem!) expectEqual(0, res) let res2 = sem_unlink(semaphoreName) From ae60618f3b879b5a4f6c35af706964a7572ef6d2 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 20 Sep 2019 14:04:07 -0700 Subject: [PATCH 134/199] Remove resolveExtension and validateExtension Push the relevant work this was doing down into the callers. Most of them didn't want to validate the entire extension and force its generic parameters, they just wanted to validate the nominal type. We must eagerly validate the generic signature of extensions, though. This avoids a class of cycles where non-generic members of an extension with a generic signaure will call through to getGenericSignatureOfContext and force the generic signature anyways. When this calls through to protocol witness matching, the signature can be recursively computed. --- include/swift/AST/LazyResolver.h | 6 --- lib/AST/ConformanceLookupTable.cpp | 4 +- lib/AST/Type.cpp | 4 +- lib/Sema/IDETypeCheckingRequests.cpp | 4 +- lib/Sema/TypeCheckDecl.cpp | 58 ++++++++++--------------- lib/Sema/TypeCheckProtocolInference.cpp | 18 +++++--- lib/Sema/TypeChecker.cpp | 10 +++-- lib/Sema/TypeChecker.h | 4 -- 8 files changed, 47 insertions(+), 61 deletions(-) diff --git a/include/swift/AST/LazyResolver.h b/include/swift/AST/LazyResolver.h index be8a01bc911ca..970cb7ccfa26d 100644 --- a/include/swift/AST/LazyResolver.h +++ b/include/swift/AST/LazyResolver.h @@ -60,12 +60,6 @@ class LazyResolver { /// consistency and provides the value a type. virtual void resolveDeclSignature(ValueDecl *VD) = 0; - /// Resolve the type of an extension. - /// - /// This can be called to ensure that the members of an extension can be - /// considered to be members of the extended type. - virtual void resolveExtension(ExtensionDecl *ext) = 0; - /// Resolve any implicitly-declared constructors within the given nominal. virtual void resolveImplicitConstructors(NominalTypeDecl *nominal) = 0; diff --git a/lib/AST/ConformanceLookupTable.cpp b/lib/AST/ConformanceLookupTable.cpp index bbe68bc18c6e4..0e48505ff16c0 100644 --- a/lib/AST/ConformanceLookupTable.cpp +++ b/lib/AST/ConformanceLookupTable.cpp @@ -798,8 +798,8 @@ ConformanceLookupTable::getConformance(NominalTypeDecl *nominal, // Everything about this conformance is nailed down, so we can now ensure that // the extension is fully resolved. if (auto resolver = nominal->getASTContext().getLazyResolver()) { - if (auto ED = dyn_cast(conformingDC)) { - resolver->resolveExtension(ED); + if (auto ext = dyn_cast(conformingDC)) { + resolver->resolveDeclSignature(ext->getExtendedNominal()); } else { resolver->resolveDeclSignature(cast(conformingDC)); } diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 652f0bca3a2da..eb8f82f8365b0 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1098,8 +1098,8 @@ CanType TypeBase::computeCanonicalType() { assert(resolver && "Need to resolve generic parameter depth"); if (auto decl = gpDecl->getDeclContext()->getInnermostDeclarationDeclContext()) - if (auto valueDecl = dyn_cast(decl)) - resolver->resolveDeclSignature(valueDecl); + if (auto valueDecl = decl->getAsGenericContext()) + (void)valueDecl->getGenericSignature(); } assert(gpDecl->getDepth() != GenericTypeParamDecl::InvalidDepth && diff --git a/lib/Sema/IDETypeCheckingRequests.cpp b/lib/Sema/IDETypeCheckingRequests.cpp index 2cd7c318a31f6..efa924be57178 100644 --- a/lib/Sema/IDETypeCheckingRequests.cpp +++ b/lib/Sema/IDETypeCheckingRequests.cpp @@ -56,9 +56,7 @@ static bool isExtensionAppliedInternal(const DeclContext *DC, Type BaseTy, if (!ED->isConstrainedExtension()) return true; - TypeChecker *TC = &TypeChecker::createForContext((DC->getASTContext())); - TC->validateExtension(const_cast(ED)); - + (void)TypeChecker::createForContext(DC->getASTContext()); GenericSignature *genericSig = ED->getGenericSignature(); SubstitutionMap substMap = BaseTy->getContextSubstitutionMap( DC->getParentModule(), ED->getExtendedNominal()); diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 84d5d2fe97e7c..d5b8a08f173cf 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -3086,9 +3086,14 @@ class DeclChecker : public DeclVisitor { return; } - TC.validateExtension(ED); + // Validate the nominal type declaration being extended. + TC.validateDecl(nominal); + // Don't bother computing the generic signature if the extended nominal + // type didn't pass validation so we don't crash. + if (!nominal->isInvalid()) + (void)ED->getGenericSignature(); + ED->setValidationToChecked(); - extType = ED->getExtendedType(); if (extType && !extType->hasError()) { // The first condition catches syntactic forms like // protocol A & B { ... } // may be protocols or typealiases @@ -3757,7 +3762,20 @@ void TypeChecker::validateDecl(ValueDecl *D) { if (!nominal->hasValidSignature()) return; } else if (auto ext = dyn_cast(dc)) { - validateExtension(ext); + // If we're currently validating, or have already validated this extension, + // there's nothing more to do now. + if (!ext->hasValidationStarted()) { + DeclValidationRAII IBV(ext); + + if (auto *nominal = ext->getExtendedNominal()) { + // Validate the nominal type declaration being extended. + validateDecl(nominal); + + // Eagerly validate the generic signature of the extension. + if (!nominal->isInvalid()) + (void)ext->getGenericSignature(); + } + } if (!ext->hasValidSignature()) return; } @@ -3819,7 +3837,7 @@ void TypeChecker::validateDecl(ValueDecl *D) { case DeclKind::OpaqueType: { auto opaque = cast(D); - DeclValidationRAII IBV(opaque); + opaque->setValidationToChecked(); break; } @@ -3828,11 +3846,7 @@ void TypeChecker::validateDecl(ValueDecl *D) { case DeclKind::Class: { auto nominal = cast(D); nominal->computeType(); - - // Check generic parameters, if needed. - DeclValidationRAII IBV(nominal); - (void)nominal->getGenericSignature(); - nominal->setSignatureIsValidated(); + nominal->setValidationToChecked(); if (auto *ED = dyn_cast(nominal)) { // @objc enums use their raw values as the value representation, so we @@ -3848,11 +3862,7 @@ void TypeChecker::validateDecl(ValueDecl *D) { auto proto = cast(D); if (!proto->hasInterfaceType()) proto->computeType(); - - // Validate the generic type signature, which is just . - DeclValidationRAII IBV(proto); - (void)proto->getGenericSignature(); - proto->setSignatureIsValidated(); + proto->setValidationToChecked(); break; } @@ -4349,26 +4359,6 @@ ExtendedTypeRequest::evaluate(Evaluator &eval, ExtensionDecl *ext) const { return extendedType; } -void TypeChecker::validateExtension(ExtensionDecl *ext) { - // If we're currently validating, or have already validated this extension, - // there's nothing more to do now. - if (ext->hasValidationStarted()) - return; - - DeclValidationRAII IBV(ext); - - if (auto *nominal = ext->getExtendedNominal()) { - // Validate the nominal type declaration being extended. - validateDecl(nominal); - - // FIXME: validateExtension is going to disappear soon. In the mean time - // don't bother computing the generic signature if the extended nominal type - // didn't pass validation so we don't crash. - if (!nominal->isInvalid()) - (void)ext->getGenericSignature(); - } -} - /// Build a default initializer string for the given pattern. /// /// This string is suitable for display in diagnostics. diff --git a/lib/Sema/TypeCheckProtocolInference.cpp b/lib/Sema/TypeCheckProtocolInference.cpp index ead35bb9bac96..fe3b6844c3cb2 100644 --- a/lib/Sema/TypeCheckProtocolInference.cpp +++ b/lib/Sema/TypeCheckProtocolInference.cpp @@ -188,15 +188,17 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses( // Invalid case. if (extendedNominal == nullptr) return true; - + + // Validate the nominal type being extended. + tc.validateDecl(extendedNominal); + if (extendedNominal->isInvalid()) + return true; + // Assume unconstrained concrete extensions we found witnesses in are // always viable. if (!isa(extendedNominal)) return !extension->isConstrainedExtension(); - - // Build a generic signature. - tc.validateExtension(extension); - + // FIXME: The extension may not have a generic signature set up yet as // resolving signatures may trigger associated type inference. This cycle // is now detectable and we should look into untangling it @@ -204,6 +206,9 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses( if (!extension->hasComputedGenericSignature()) return true; + // Build a generic signature. + auto *extensionSig = extension->getGenericSignature(); + // The condition here is a bit more fickle than // `isExtensionApplied`. That check would prematurely reject // extensions like `P where AssocType == T` if we're relying on a @@ -212,8 +217,7 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses( // because those have to be explicitly declared on the type somewhere // so won't be affected by whatever answer inference comes up with. auto selfTy = extension->getSelfInterfaceType(); - for (const Requirement &reqt - : extension->getGenericSignature()->getRequirements()) { + for (const Requirement &reqt : extensionSig->getRequirements()) { switch (reqt.getKind()) { case RequirementKind::Conformance: case RequirementKind::Superclass: diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp index 8382e4196c16a..0e22007ee1ba5 100644 --- a/lib/Sema/TypeChecker.cpp +++ b/lib/Sema/TypeChecker.cpp @@ -614,10 +614,14 @@ void swift::typeCheckCompletionDecl(Decl *D) { DiagnosticSuppression suppression(Ctx.Diags); TypeChecker &TC = createTypeChecker(Ctx); - if (auto ext = dyn_cast(D)) - TC.validateExtension(ext); - else + if (auto ext = dyn_cast(D)) { + if (auto *nominal = ext->getExtendedNominal()) { + // Validate the nominal type declaration being extended. + TC.validateDecl(nominal); + } + } else { TC.validateDecl(cast(D)); + } } void swift::typeCheckPatternBinding(PatternBindingDecl *PBD, diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 5aec93319d502..bb70fd474065a 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -1015,10 +1015,6 @@ class TypeChecker final : public LazyResolver { validateDecl(VD); } - virtual void resolveExtension(ExtensionDecl *ext) override { - validateExtension(ext); - } - virtual void resolveImplicitConstructors(NominalTypeDecl *nominal) override { addImplicitConstructors(nominal); } From b135928125d09c1f48fd0f7265874286c7e74bf0 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 20 Sep 2019 14:32:34 -0700 Subject: [PATCH 135/199] Drop CheckingWithValidSignature from the validation state machine Now that the generic signature is computable on demand, this predicate is doubly useless. All of the callers intended to ask "hasInterfaceType" anyways. --- include/swift/AST/Decl.h | 16 -------------- lib/AST/ASTVerifier.cpp | 2 +- lib/AST/Decl.cpp | 8 ------- lib/IDE/CodeCompletion.cpp | 4 ++-- lib/Sema/CSDiag.cpp | 4 ++-- lib/Sema/CSDiagnostics.cpp | 2 +- lib/Sema/CSSimplify.cpp | 2 +- lib/Sema/CalleeCandidateInfo.cpp | 2 +- lib/Sema/CodeSynthesis.cpp | 12 +++++------ lib/Sema/ConstraintSystem.cpp | 2 +- lib/Sema/TypeCheckAttr.cpp | 2 +- lib/Sema/TypeCheckDecl.cpp | 28 +++++++------------------ lib/Sema/TypeCheckNameLookup.cpp | 2 +- lib/Sema/TypeCheckProtocol.cpp | 8 +++---- lib/Sema/TypeCheckProtocolInference.cpp | 6 +++--- lib/Sema/TypeChecker.h | 2 +- lib/Serialization/Serialization.cpp | 2 +- 17 files changed, 34 insertions(+), 70 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 5bb8cff18ab2b..e1801d51450dd 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -279,7 +279,6 @@ class alignas(1 << DeclAlignInBits) Decl { enum class ValidationState { Unchecked, Checking, - CheckingWithValidSignature, Checked, }; @@ -850,19 +849,11 @@ class alignas(1 << DeclAlignInBits) Decl { case ValidationState::Checked: return false; case ValidationState::Checking: - case ValidationState::CheckingWithValidSignature: return true; } llvm_unreachable("Unknown ValidationState"); } - /// Update the validation state for the declaration to allow access to the - /// generic signature. - void setSignatureIsValidated() { - assert(getValidationState() == ValidationState::Checking); - setValidationState(ValidationState::CheckingWithValidSignature); - } - bool hasValidationStarted() const { return getValidationState() > ValidationState::Unchecked; } @@ -1769,11 +1760,6 @@ class ExtensionDecl final : public GenericContext, public Decl, void setInherited(MutableArrayRef i) { Inherited = i; } - /// Whether we have fully checked the extension signature. - bool hasValidSignature() const { - return getValidationState() > ValidationState::CheckingWithValidSignature; - } - bool hasDefaultAccessLevel() const { return Bits.ExtensionDecl.DefaultAndMaxAccessLevel != 0; } @@ -2608,8 +2594,6 @@ class ValueDecl : public Decl { /// Set the interface type for the given value. void setInterfaceType(Type type); - - bool hasValidSignature() const; /// isInstanceMember - Determine whether this value is an instance member /// of an enum or protocol. diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp index 1f047fac12380..414d4ee2fbad3 100644 --- a/lib/AST/ASTVerifier.cpp +++ b/lib/AST/ASTVerifier.cpp @@ -2968,7 +2968,7 @@ class Verifier : public ASTWalker { void verifyChecked(AbstractFunctionDecl *AFD) { PrettyStackTraceDecl debugStack("verifying AbstractFunctionDecl", AFD); - if (!AFD->hasValidSignature()) { + if (!AFD->hasInterfaceType()) { if (isa(AFD) && AFD->isImplicit()) return; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 91dda4c2edc2d..bbc21ece7faf2 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2720,14 +2720,6 @@ void ValueDecl::setInterfaceType(Type type) { TypeAndAccess.setPointer(type); } -bool ValueDecl::hasValidSignature() const { - if (!hasInterfaceType()) - return false; - // FIXME -- The build blows up if the correct code is used: - // return getValidationState() > ValidationState::CheckingWithValidSignature; - return getValidationState() != ValidationState::Checking; -} - Optional ValueDecl::getObjCRuntimeName( bool skipIsObjCResolution) const { if (auto func = dyn_cast(this)) diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index 11bb4c8b5c9a9..e88a46edf673f 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -2046,7 +2046,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { auto *GenericSig = VD->getInnermostDeclContext() ->getGenericSignatureOfContext(); - assert(VD->hasValidSignature()); + assert(VD->hasInterfaceType()); Type T = VD->getInterfaceType(); if (ExprType) { @@ -2135,7 +2135,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { addValueBaseName(Builder, Name); setClangDeclKeywords(VD, Pairs, Builder); - if (!VD->hasValidSignature()) + if (!VD->hasInterfaceType()) return; // Add a type annotation. diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp index bf483ab26de16..8ed072fcc150a 100644 --- a/lib/Sema/CSDiag.cpp +++ b/lib/Sema/CSDiag.cpp @@ -1329,7 +1329,7 @@ DeclContext *FailureDiagnosis::findDeclContext(Expr *subExpr) const { // variables would be accessible to name lookup of the subexpression and // may thus leak in. Reset them to UnresolvedTypes for safe measures. assert(llvm::all_of(*closure->getParameters(), [](const ParamDecl *PD) { - if (PD->hasValidSignature()) { + if (PD->hasInterfaceType()) { auto paramTy = PD->getType(); return !(paramTy->hasTypeVariable() || paramTy->hasError()); } @@ -5345,7 +5345,7 @@ diagnoseAmbiguousMultiStatementClosure(ClosureExpr *closure) { if (auto DRE = dyn_cast(childExpr)) { if (auto param = dyn_cast(DRE->getDecl())) { auto paramType = - param->hasValidSignature() ? param->getType() : Type(); + param->hasInterfaceType() ? param->getType() : Type(); if (!paramType || paramType->hasTypeVariable()) { hasUnresolvedParams = true; return nullptr; diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 20c67ee62734d..39772d9b1e262 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -1473,7 +1473,7 @@ bool TrailingClosureAmbiguityFailure::diagnoseAsNote() { const ParamDecl *param = paramList->getArray().back(); // Sanity-check that the trailing closure corresponds to this parameter. - if (!param->hasValidSignature() || + if (!param->hasInterfaceType() || !param->getInterfaceType()->is()) return false; diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index a4ac0b781d88d..1bae5d7a2d93c 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -2144,7 +2144,7 @@ static ConstraintFix *fixPropertyWrapperFailure( }; auto applyFix = [&](Fix fix, VarDecl *decl, Type type) -> ConstraintFix * { - if (!decl->hasValidSignature() || !type) + if (!decl->hasInterfaceType() || !type) return nullptr; if (baseTy->isEqual(type)) diff --git a/lib/Sema/CalleeCandidateInfo.cpp b/lib/Sema/CalleeCandidateInfo.cpp index 5c71eac3ab4cb..7a2f64ea75f73 100644 --- a/lib/Sema/CalleeCandidateInfo.cpp +++ b/lib/Sema/CalleeCandidateInfo.cpp @@ -61,7 +61,7 @@ OverloadCandidate::OverloadCandidate(ValueDecl *decl, bool skipCurriedSelf) : declOrExpr(decl), skipCurriedSelf(skipCurriedSelf), substituted(false) { if (auto *PD = dyn_cast(decl)) { - if (PD->hasValidSignature()) + if (PD->hasInterfaceType()) entityType = PD->getType(); else entityType = PD->getASTContext().TheUnresolvedType; diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index 962d8a4be482c..a55232dfa4de2 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -540,7 +540,7 @@ synthesizeDesignatedInitOverride(AbstractFunctionDecl *fn, void *context) { auto *superclassCtor = (ConstructorDecl *) context; - if (!superclassCtor->hasValidSignature()) + if (!superclassCtor->hasInterfaceType()) ctx.getLazyResolver()->resolveDeclSignature(superclassCtor); // Reference to super.init. @@ -856,9 +856,9 @@ static void addImplicitConstructorsToStruct(StructDecl *decl, ASTContext &ctx) { if (!var->isMemberwiseInitialized(/*preferDeclaredProperties=*/true)) continue; - if (!var->hasValidSignature()) + if (!var->hasInterfaceType()) ctx.getLazyResolver()->resolveDeclSignature(var); - if (!var->hasValidSignature()) + if (!var->hasInterfaceType()) return; } } @@ -923,9 +923,9 @@ static void addImplicitConstructorsToClass(ClassDecl *decl, ASTContext &ctx) { if (!decl->hasClangNode()) { for (auto member : decl->getMembers()) { if (auto ctor = dyn_cast(member)) { - if (!ctor->hasValidSignature()) + if (!ctor->hasInterfaceType()) ctx.getLazyResolver()->resolveDeclSignature(ctor); - if (!ctor->hasValidSignature()) + if (!ctor->hasInterfaceType()) return; } } @@ -1081,7 +1081,7 @@ static void addImplicitConstructorsToClass(ClassDecl *decl, ASTContext &ctx) { // We have a designated initializer. Create an override of it. // FIXME: Validation makes sure we get a generic signature here. - if (!decl->hasValidSignature()) + if (!decl->hasInterfaceType()) ctx.getLazyResolver()->resolveDeclSignature(decl); if (auto ctor = createDesignatedInitOverride( diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index de3064005e9d0..d0db92464bcac 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -819,7 +819,7 @@ Type ConstraintSystem::getUnopenedTypeOfReference(VarDecl *value, Type baseType, if (auto *param = dyn_cast(var)) return getType(param); - if (!var->hasValidSignature()) { + if (!var->hasInterfaceType()) { if (!var->isInvalid()) { TC.diagnose(var->getLoc(), diag::recursive_decl_reference, var->getDescriptiveKind(), var->getName()); diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index fc58db7630b06..f58d0927230ff 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -1151,7 +1151,7 @@ static bool hasSingleNonVariadicParam(SubscriptDecl *decl, return false; auto *index = indices->get(0); - if (index->isVariadic() || !index->hasValidSignature()) + if (index->isVariadic() || !index->hasInterfaceType()) return false; if (ignoreLabel) { diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index d5b8a08f173cf..de19d1ee5de24 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2881,7 +2881,7 @@ class DeclChecker : public DeclVisitor { checkUnsupportedNestedType(PD); TC.validateDecl(PD); - if (!PD->hasValidSignature()) + if (!PD->hasInterfaceType()) return; auto *SF = PD->getParentSourceFile(); @@ -3731,12 +3731,12 @@ void TypeChecker::validateDecl(ValueDecl *D) { return; // Handling validation failure due to re-entrancy is left - // up to the caller, who must call hasValidSignature() to + // up to the caller, who must call hasInterfaceType() to // check that validateDecl() returned a fully-formed decl. if (D->hasValidationStarted()) { // If this isn't reentrant (i.e. D has already been validated), the // signature better be valid. - assert(D->isBeingValidated() || D->hasValidSignature()); + assert(D->isBeingValidated() || D->hasInterfaceType()); return; } @@ -3759,7 +3759,7 @@ void TypeChecker::validateDecl(ValueDecl *D) { auto dc = D->getDeclContext(); if (auto nominal = dyn_cast(dc)) { validateDecl(nominal); - if (!nominal->hasValidSignature()) + if (!nominal->hasInterfaceType()) return; } else if (auto ext = dyn_cast(dc)) { // If we're currently validating, or have already validated this extension, @@ -3776,14 +3776,14 @@ void TypeChecker::validateDecl(ValueDecl *D) { (void)ext->getGenericSignature(); } } - if (!ext->hasValidSignature()) + if (ext->getValidationState() == Decl::ValidationState::Checking) return; } // Validating the parent may have triggered validation of this declaration, // so just return if that was the case. if (D->hasValidationStarted()) { - assert(D->hasValidSignature()); + assert(D->hasInterfaceType()); return; } @@ -3940,7 +3940,7 @@ void TypeChecker::validateDecl(ValueDecl *D) { if (auto accessor = dyn_cast(FD)) { auto *storage = accessor->getStorage(); validateDecl(storage); - if (!storage->hasValidSignature()) + if (!storage->hasInterfaceType()) return; } @@ -4046,7 +4046,6 @@ void TypeChecker::validateDecl(ValueDecl *D) { FD->getBodyResultTypeLoc(), resolution); // FIXME: Roll all of this interface type computation into a request. FD->computeType(); - FD->setSignatureIsValidated(); // Member functions need some special validation logic. if (FD->getDeclContext()->isTypeContext()) { @@ -4091,11 +4090,6 @@ void TypeChecker::validateDecl(ValueDecl *D) { typeCheckParameterList(CD->getParameters(), res, TypeResolverContext::AbstractFunctionDecl); CD->computeType(); - - // We want the constructor to be available for name lookup as soon - // as it has a valid interface type. - CD->setSignatureIsValidated(); - break; } @@ -4108,8 +4102,6 @@ void TypeChecker::validateDecl(ValueDecl *D) { typeCheckParameterList(DD->getParameters(), res, TypeResolverContext::AbstractFunctionDecl); DD->computeType(); - - DD->setSignatureIsValidated(); break; } @@ -4125,8 +4117,6 @@ void TypeChecker::validateDecl(ValueDecl *D) { SD->getElementTypeLoc(), res); SD->computeType(); - SD->setSignatureIsValidated(); - if (SD->getOpaqueResultTypeDecl()) { if (auto SF = SD->getInnermostDeclContext()->getParentSourceFile()) { SF->markDeclWithOpaqueResultTypeAsValidated(SD); @@ -4170,8 +4160,6 @@ void TypeChecker::validateDecl(ValueDecl *D) { // type. EED->computeType(); - EED->setSignatureIsValidated(); - if (auto argTy = EED->getArgumentInterfaceType()) { assert(argTy->isMaterializable()); (void) argTy; @@ -4181,7 +4169,7 @@ void TypeChecker::validateDecl(ValueDecl *D) { } } - assert(D->hasValidSignature()); + assert(D->hasInterfaceType()); } llvm::Expected diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp index dc7979df10424..d51f8508c48ba 100644 --- a/lib/Sema/TypeCheckNameLookup.cpp +++ b/lib/Sema/TypeCheckNameLookup.cpp @@ -497,7 +497,7 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, auto *protocol = cast(assocType->getDeclContext()); // If we're validating the protocol recursively, bail out. - if (!protocol->hasValidSignature()) + if (!protocol->hasInterfaceType()) continue; auto conformance = conformsToProtocol(type, protocol, dc, diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index ea05d1a83dbb3..5071d2dd3e83e 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -330,7 +330,7 @@ swift::matchWitness( return RequirementMatch(witness, MatchKind::KindConflict); // If the witness has not been validated yet, do so now. - if (!witness->hasValidSignature()) { + if (!witness->hasInterfaceType()) { auto &ctx = dc->getASTContext(); ctx.getLazyResolver()->resolveDeclSignature(witness); } @@ -340,7 +340,7 @@ swift::matchWitness( return RequirementMatch(witness, MatchKind::WitnessInvalid); // If we're currently validating the witness, bail out. - if (!witness->hasValidSignature()) + if (!witness->hasInterfaceType()) return RequirementMatch(witness, MatchKind::Circularity); // Get the requirement and witness attributes. @@ -3854,11 +3854,11 @@ void ConformanceChecker::resolveValueWitnesses() { continue; } - // Make sure we've validated the requirement. + // Make sure we've got an interface type. if (!requirement->hasInterfaceType()) TC.validateDecl(requirement); - if (requirement->isInvalid() || !requirement->hasValidSignature()) { + if (requirement->isInvalid() || !requirement->hasInterfaceType()) { Conformance->setInvalid(); continue; } diff --git a/lib/Sema/TypeCheckProtocolInference.cpp b/lib/Sema/TypeCheckProtocolInference.cpp index fe3b6844c3cb2..afdfa51b50e98 100644 --- a/lib/Sema/TypeCheckProtocolInference.cpp +++ b/lib/Sema/TypeCheckProtocolInference.cpp @@ -453,7 +453,7 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses( // Validate the requirement. tc.validateDecl(req); - if (req->isInvalid() || !req->hasValidSignature()) + if (req->isInvalid() || !req->hasInterfaceType()) continue; // Check whether any of the associated types we care about are @@ -501,7 +501,7 @@ static Type getWitnessTypeForMatching(TypeChecker &tc, if (!witness->hasInterfaceType()) tc.validateDecl(witness); - if (witness->isInvalid() || !witness->hasValidSignature()) + if (witness->isInvalid() || !witness->hasInterfaceType()) return Type(); if (!witness->getDeclContext()->isTypeContext()) { @@ -2039,7 +2039,7 @@ void ConformanceChecker::resolveSingleWitness(ValueDecl *requirement) { if (!requirement->hasInterfaceType()) TC.validateDecl(requirement); - if (requirement->isInvalid() || !requirement->hasValidSignature()) { + if (requirement->isInvalid() || !requirement->hasInterfaceType()) { Conformance->setInvalid(); return; } diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index bb70fd474065a..fb370988fafeb 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -1423,7 +1423,7 @@ class TypeChecker final : public LazyResolver { [&](VarDecl *var) -> Type { validateDecl(var); - if (!var->hasValidSignature() || var->isInvalid()) + if (!var->hasInterfaceType() || var->isInvalid()) return ErrorType::get(Context); return wantInterfaceType ? value->getInterfaceType() diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 78695d7191692..f1b305a365eb9 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -3262,7 +3262,7 @@ class Serializer::DeclSerializer : public DeclVisitor { // // FIXME: Once accessor synthesis and getInterfaceType() itself are // request-ified this goes away. - if (!fn->hasValidSignature()) { + if (!fn->hasInterfaceType()) { assert(fn->isImplicit()); S.M->getASTContext().getLazyResolver()->resolveDeclSignature( const_cast(fn)); From a42bdf4c20eafaaceb65206b984f3497edac7ef5 Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Wed, 18 Sep 2019 15:50:25 -0700 Subject: [PATCH 136/199] [Parse] Simplify parseIdentifierDeclName() As a preparation for syntax parsing. --- lib/Parse/ParseDecl.cpp | 98 ++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 64 deletions(-) diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index aac270c73ddae..2b3108bae6392 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -3518,16 +3518,10 @@ ParserStatus Parser::parseInheritance(SmallVectorImpl &Inherited, return Status; } -enum class TokenProperty { - None, - StartsWithLess, -}; - static ParserStatus parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &Loc, - StringRef DeclKindName, tok ResyncT1, tok ResyncT2, - tok ResyncT3, tok ResyncT4, - TokenProperty ResyncP1) { + StringRef DeclKindName, + llvm::function_ref canRecover) { if (P.Tok.is(tok::identifier)) { Loc = P.consumeIdentifier(&Result); @@ -3566,9 +3560,7 @@ parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &Loc, .fixItReplace(P.Tok.getLoc(), "`" + P.Tok.getText().str() + "`"); // Recover if the next token is one of the expected tokens. - auto Next = P.peekToken(); - if (Next.isAny(ResyncT1, ResyncT2, ResyncT3, ResyncT4) || - (ResyncP1 != TokenProperty::None && P.startsWithLess(Next))) { + if (canRecover(P.peekToken())) { llvm::SmallString<32> Name(P.Tok.getText()); // Append an invalid character so that nothing can resolve to this name. Name += "#"; @@ -3585,38 +3577,6 @@ parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &Loc, return makeParserError(); } -static ParserStatus -parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &L, - StringRef DeclKindName, tok ResyncT1, tok ResyncT2) { - return parseIdentifierDeclName(P, Result, L, DeclKindName, ResyncT1, ResyncT2, - tok::NUM_TOKENS, tok::NUM_TOKENS, - TokenProperty::None); -} - -static ParserStatus -parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &L, - StringRef DeclKindName, tok ResyncT1, tok ResyncT2, - tok ResyncT3, tok ResyncT4) { - return parseIdentifierDeclName(P, Result, L, DeclKindName, ResyncT1, ResyncT2, - ResyncT3, ResyncT4, TokenProperty::None); -} - -static ParserStatus -parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &L, - StringRef DeclKindName, tok ResyncT1, tok ResyncT2, - TokenProperty ResyncP1) { - return parseIdentifierDeclName(P, Result, L, DeclKindName, ResyncT1, ResyncT2, - tok::NUM_TOKENS, tok::NUM_TOKENS, ResyncP1); -} - -static ParserStatus -parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &L, - StringRef DeclKindName, tok ResyncT1, tok ResyncT2, - tok ResyncT3, TokenProperty ResyncP1) { - return parseIdentifierDeclName(P, Result, L, DeclKindName, ResyncT1, ResyncT2, - ResyncT3, tok::NUM_TOKENS, ResyncP1); -} - /// Add a fix-it to remove the space in consecutive identifiers. /// Add a camel-cased option if it is different than the first option. void Parser::diagnoseConsecutiveIDs(StringRef First, SourceLoc FirstLoc, @@ -4135,8 +4095,9 @@ parseDeclTypeAlias(Parser::ParseDeclOptions Flags, DeclAttributes &Attributes) { SourceLoc IdLoc; ParserStatus Status; - Status |= parseIdentifierDeclName(*this, Id, IdLoc, "typealias", - tok::colon, tok::equal); + Status |= parseIdentifierDeclName( + *this, Id, IdLoc, "typealias", + [](const Token &next) { return next.isAny(tok::colon, tok::equal); }); if (Status.isError()) { TmpCtxt->setTransparent(); return nullptr; @@ -4250,9 +4211,10 @@ ParserResult Parser::parseDeclAssociatedType(Parser::ParseDeclOptions } else { AssociatedTypeLoc = consumeToken(tok::kw_associatedtype); } - - Status = parseIdentifierDeclName(*this, Id, IdLoc, "associatedtype", - tok::colon, tok::equal); + + Status = parseIdentifierDeclName( + *this, Id, IdLoc, "associatedtype", + [](const Token &next) { return next.isAny(tok::colon, tok::equal); }); if (Status.isError()) return nullptr; @@ -5473,8 +5435,10 @@ ParserResult Parser::parseDeclFunc(SourceLoc StaticLoc, // because we're aggressive about recovering/providing good diagnostics for // beginners. auto NameStatus = parseIdentifierDeclName( - *this, SimpleName, NameLoc, "function", tok::l_paren, tok::arrow, - tok::l_brace, TokenProperty::StartsWithLess); + *this, SimpleName, NameLoc, "function", [&](const Token &next) { + return next.isAny(tok::l_paren, tok::arrow, tok::l_brace) || + startsWithLess(next); + }); if (NameStatus.isError()) return nullptr; } @@ -5717,9 +5681,10 @@ ParserResult Parser::parseDeclEnum(ParseDeclOptions Flags, SourceLoc EnumNameLoc; ParserStatus Status; - Status |= parseIdentifierDeclName(*this, EnumName, EnumNameLoc, "enum", - tok::colon, tok::l_brace, - TokenProperty::StartsWithLess); + Status |= parseIdentifierDeclName( + *this, EnumName, EnumNameLoc, "enum", [&](const Token &next) { + return next.isAny(tok::colon, tok::l_brace) || startsWithLess(next); + }); if (Status.isError()) return nullptr; @@ -5823,9 +5788,11 @@ Parser::parseDeclEnumCase(ParseDeclOptions Flags, } if (Tok.is(tok::identifier)) { - Status |= parseIdentifierDeclName(*this, Name, NameLoc, "enum 'case'", - tok::l_paren, tok::kw_case, tok::colon, - tok::r_brace); + Status |= parseIdentifierDeclName( + *this, Name, NameLoc, "enum 'case'", [](const Token &next) { + return next.isAny(tok::l_paren, tok::kw_case, tok::colon, + tok::r_brace); + }); assert(Status.isSuccess()); if (DotLoc.isValid()) diagnose(DotLoc, diag::enum_case_dot_prefix) @@ -5997,9 +5964,10 @@ ParserResult Parser::parseDeclStruct(ParseDeclOptions Flags, SourceLoc StructNameLoc; ParserStatus Status; - Status |= parseIdentifierDeclName(*this, StructName, StructNameLoc, "struct", - tok::colon, tok::l_brace, - TokenProperty::StartsWithLess); + Status |= parseIdentifierDeclName( + *this, StructName, StructNameLoc, "struct", [&](const Token &next) { + return next.isAny(tok::colon, tok::l_brace) || startsWithLess(next); + }); if (Status.isError()) return nullptr; @@ -6088,9 +6056,10 @@ ParserResult Parser::parseDeclClass(ParseDeclOptions Flags, SourceLoc ClassNameLoc; ParserStatus Status; - Status |= parseIdentifierDeclName(*this, ClassName, ClassNameLoc, "class", - tok::colon, tok::l_brace, - TokenProperty::StartsWithLess); + Status |= parseIdentifierDeclName( + *this, ClassName, ClassNameLoc, "class", [&](const Token &next) { + return next.isAny(tok::colon, tok::l_brace) || startsWithLess(next); + }); if (Status.isError()) return nullptr; @@ -6207,8 +6176,9 @@ parseDeclProtocol(ParseDeclOptions Flags, DeclAttributes &Attributes) { Identifier ProtocolName; ParserStatus Status; - Status |= parseIdentifierDeclName(*this, ProtocolName, NameLoc, "protocol", - tok::colon, tok::l_brace); + Status |= parseIdentifierDeclName( + *this, ProtocolName, NameLoc, "protocol", + [&](const Token &next) { return next.isAny(tok::colon, tok::l_brace); }); if (Status.isError()) return nullptr; From fde58a9e15c97532a15e5b675de166f5d1199fad Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Wed, 18 Sep 2019 15:43:07 -0700 Subject: [PATCH 137/199] [ASTGen] Adjust geneate() function signatures 'generate()' receives `const` reference to `SomeSyntax`. This should prevent unnecessary reference counter operations. --- include/swift/Parse/ASTGen.h | 169 +++++++++++++++---------- include/swift/Syntax/Syntax.h | 4 +- include/swift/Syntax/SyntaxNodes.h.gyb | 4 +- lib/Parse/ASTGen.cpp | 132 +++++++++++-------- lib/Syntax/Syntax.cpp | 4 +- lib/Syntax/SyntaxNodes.cpp.gyb | 4 +- 6 files changed, 190 insertions(+), 127 deletions(-) diff --git a/include/swift/Parse/ASTGen.h b/include/swift/Parse/ASTGen.h index 591c8034548ea..31e6757013fdd 100644 --- a/include/swift/Parse/ASTGen.h +++ b/include/swift/Parse/ASTGen.h @@ -31,87 +31,130 @@ class ASTGen { Parser &P; - // FIXME: remove when Syntax can represent all types and ASTGen can handle them + // FIXME: remove when Syntax can represent all types and ASTGen can handle + // them /// Types that cannot be represented by Syntax or generated by ASTGen. llvm::DenseMap Types; llvm::DenseMap ParsedDeclAttrs; public: - ASTGen(ASTContext &Context, Parser &P) - : Context(Context), P(P) {} - - SourceLoc generate(syntax::TokenSyntax Tok, SourceLoc &Loc); - - Expr *generate(syntax::IntegerLiteralExprSyntax &Expr, SourceLoc &Loc); - Expr *generate(syntax::FloatLiteralExprSyntax &Expr, SourceLoc &Loc); - Expr *generate(syntax::NilLiteralExprSyntax &Expr, SourceLoc &Loc); - Expr *generate(syntax::BooleanLiteralExprSyntax &Expr, SourceLoc &Loc); - Expr *generate(syntax::PoundFileExprSyntax &Expr, SourceLoc &Loc); - Expr *generate(syntax::PoundLineExprSyntax &Expr, SourceLoc &Loc); - Expr *generate(syntax::PoundColumnExprSyntax &Expr, SourceLoc &Loc); - Expr *generate(syntax::PoundFunctionExprSyntax &Expr, SourceLoc &Loc); - Expr *generate(syntax::PoundDsohandleExprSyntax &Expr, SourceLoc &Loc); - Expr *generate(syntax::UnknownExprSyntax &Expr, SourceLoc &Loc); - - TypeRepr *generate(syntax::TypeSyntax Type, SourceLoc &Loc); - TypeRepr *generate(syntax::SomeTypeSyntax Type, SourceLoc &Loc); - TypeRepr *generate(syntax::CompositionTypeSyntax Type, SourceLoc &Loc); - TypeRepr *generate(syntax::SimpleTypeIdentifierSyntax Type, SourceLoc &Loc); - TypeRepr *generate(syntax::MemberTypeIdentifierSyntax Type, SourceLoc &Loc); - TypeRepr *generate(syntax::DictionaryTypeSyntax Type, SourceLoc &Loc); - TypeRepr *generate(syntax::ArrayTypeSyntax Type, SourceLoc &Loc); - TypeRepr *generate(syntax::TupleTypeSyntax Type, SourceLoc &Loc); - TypeRepr *generate(syntax::AttributedTypeSyntax Type, SourceLoc &Loc); - TypeRepr *generate(syntax::FunctionTypeSyntax Type, SourceLoc &Loc); - TypeRepr *generate(syntax::MetatypeTypeSyntax Type, SourceLoc &Loc); - TypeRepr *generate(syntax::OptionalTypeSyntax Type, SourceLoc &Loc); - TypeRepr *generate(syntax::ImplicitlyUnwrappedOptionalTypeSyntax Type, SourceLoc &Loc); - TypeRepr *generate(syntax::UnknownTypeSyntax Type, SourceLoc &Loc); - - TypeRepr *generate(syntax::GenericArgumentSyntax Arg, SourceLoc &Loc); - llvm::SmallVector - generate(syntax::GenericArgumentListSyntax Args, SourceLoc &Loc); + ASTGen(ASTContext &Context, Parser &P) : Context(Context), P(P) {} - GenericParamList * - generate(syntax::GenericParameterClauseListSyntax clause, SourceLoc &Loc); - GenericParamList * - generate(syntax::GenericParameterClauseSyntax clause, SourceLoc &Loc); - Optional - generate(syntax::GenericRequirementSyntax req, SourceLoc &Loc); - LayoutConstraint - generate(syntax::LayoutConstraintSyntax req, SourceLoc &Loc); + SourceLoc generate(const syntax::TokenSyntax &Tok, const SourceLoc Loc); - /// Copy a numeric literal value into AST-owned memory, stripping underscores - /// so the semantic part of the value can be parsed by APInt/APFloat parsers. - static StringRef copyAndStripUnderscores(StringRef Orig, ASTContext &Context); +public: + //===--------------------------------------------------------------------===// + // Expressions. + + Expr *generate(const syntax::IntegerLiteralExprSyntax &Expr, + const SourceLoc Loc); + Expr *generate(const syntax::FloatLiteralExprSyntax &Expr, + const SourceLoc Loc); + Expr *generate(const syntax::NilLiteralExprSyntax &Expr, const SourceLoc Loc); + Expr *generate(const syntax::BooleanLiteralExprSyntax &Expr, + const SourceLoc Loc); + Expr *generate(const syntax::PoundFileExprSyntax &Expr, const SourceLoc Loc); + Expr *generate(const syntax::PoundLineExprSyntax &Expr, const SourceLoc Loc); + Expr *generate(const syntax::PoundColumnExprSyntax &Expr, + const SourceLoc Loc); + Expr *generate(const syntax::PoundFunctionExprSyntax &Expr, + const SourceLoc Loc); + Expr *generate(const syntax::PoundDsohandleExprSyntax &Expr, + const SourceLoc Loc); + Expr *generate(const syntax::UnknownExprSyntax &Expr, const SourceLoc Loc); private: - Expr *generateMagicIdentifierLiteralExpression(syntax::TokenSyntax PoundToken, - SourceLoc &Loc); + Expr *generateMagicIdentifierLiteralExpression( + const syntax::TokenSyntax &PoundToken, const SourceLoc Loc); - TupleTypeRepr *generateTuple(syntax::TokenSyntax LParen, - syntax::TupleTypeElementListSyntax Elements, - syntax::TokenSyntax RParen, SourceLoc &Loc, - bool IsFunction = false); + static MagicIdentifierLiteralExpr::Kind + getMagicIdentifierLiteralKind(tok Kind); + +public: + //===--------------------------------------------------------------------===// + // Types. + + TypeRepr *generate(const syntax::TypeSyntax &Type, const SourceLoc Loc); + TypeRepr *generate(const syntax::SomeTypeSyntax &Type, const SourceLoc Loc); + TypeRepr *generate(const syntax::CompositionTypeSyntax &Type, + const SourceLoc Loc); + TypeRepr *generate(const syntax::SimpleTypeIdentifierSyntax &Type, + const SourceLoc Loc); + TypeRepr *generate(const syntax::MemberTypeIdentifierSyntax &Type, + const SourceLoc Loc); + TypeRepr *generate(const syntax::DictionaryTypeSyntax &Type, + const SourceLoc Loc); + TypeRepr *generate(const syntax::ArrayTypeSyntax &Type, const SourceLoc Loc); + TypeRepr *generate(const syntax::TupleTypeSyntax &Type, const SourceLoc Loc); + TypeRepr *generate(const syntax::AttributedTypeSyntax &Type, + const SourceLoc Loc); + TypeRepr *generate(const syntax::FunctionTypeSyntax &Type, + const SourceLoc Loc); + TypeRepr *generate(const syntax::MetatypeTypeSyntax &Type, + const SourceLoc Loc); + TypeRepr *generate(const syntax::OptionalTypeSyntax &Type, + const SourceLoc Loc); + TypeRepr *generate(const syntax::ImplicitlyUnwrappedOptionalTypeSyntax &Type, + const SourceLoc Loc); + TypeRepr *generate(const syntax::UnknownTypeSyntax &Type, + const SourceLoc Loc); + +private: + TupleTypeRepr * + generateTuple(const syntax::TokenSyntax &LParen, + const syntax::TupleTypeElementListSyntax &Elements, + const syntax::TokenSyntax &RParen, const SourceLoc Loc, + bool IsFunction = false); void gatherTypeIdentifierComponents( - syntax::TypeSyntax Component, SourceLoc &Loc, + const syntax::TypeSyntax &Component, const SourceLoc Loc, llvm::SmallVectorImpl &Components); template - TypeRepr *generateSimpleOrMemberIdentifier(T Type, SourceLoc &Loc); + TypeRepr *generateSimpleOrMemberIdentifier(const T &Type, + const SourceLoc Loc); template - ComponentIdentTypeRepr *generateIdentifier(T Type, SourceLoc &Loc); + ComponentIdentTypeRepr *generateIdentifier(const T &Type, + const SourceLoc Loc); +public: + //===--------------------------------------------------------------------===// + // Generics. + + TypeRepr *generate(const syntax::GenericArgumentSyntax &Arg, + const SourceLoc Loc); + llvm::SmallVector + generate(const syntax::GenericArgumentListSyntax &Args, const SourceLoc Loc); + + GenericParamList * + generate(const syntax::GenericParameterClauseListSyntax &clause, + const SourceLoc Loc); + GenericParamList *generate(const syntax::GenericParameterClauseSyntax &clause, + const SourceLoc Loc); + Optional + generate(const syntax::GenericRequirementSyntax &req, const SourceLoc Loc); + LayoutConstraint generate(const syntax::LayoutConstraintSyntax &req, + const SourceLoc Loc); + +public: + //===--------------------------------------------------------------------===// + // Utilities. + + /// Copy a numeric literal value into AST-owned memory, stripping underscores + /// so the semantic part of the value can be parsed by APInt/APFloat parsers. + static StringRef copyAndStripUnderscores(StringRef Orig, ASTContext &Context); + +private: StringRef copyAndStripUnderscores(StringRef Orig); + /// Advance \p Loc to the first token of the \p Node. + /// \p Loc must be the leading trivia of the first token in the tree in which + /// \p Node resides. static SourceLoc advanceLocBegin(const SourceLoc &Loc, const syntax::Syntax &Node); - static MagicIdentifierLiteralExpr::Kind getMagicIdentifierLiteralKind(tok Kind); - ValueDecl *lookupInScope(DeclName Name); void addToScope(ValueDecl *D, bool diagnoseRedefinitions = true); @@ -121,15 +164,13 @@ class ASTGen { TypeRepr *lookupType(syntax::TypeSyntax Type); public: - TypeRepr *addType(TypeRepr *Type, const SourceLoc &Loc); - - bool hasType(const SourceLoc &Loc) const; - - TypeRepr *getType(const SourceLoc &Loc) const; + void addType(TypeRepr *Type, const SourceLoc Loc); + bool hasType(const SourceLoc Loc) const; + TypeRepr *getType(const SourceLoc Loc) const; - void addDeclAttributes(DeclAttributes attrs, SourceLoc Loc); + void addDeclAttributes(DeclAttributes attrs, const SourceLoc Loc); bool hasDeclAttributes(SourceLoc Loc) const; - DeclAttributes getDeclAttributes(SourceLoc Loc) const; + DeclAttributes getDeclAttributes(const SourceLoc Loc) const; }; } // namespace swift diff --git a/include/swift/Syntax/Syntax.h b/include/swift/Syntax/Syntax.h index eef64dfaf526e..c4b2d8f227dc3 100644 --- a/include/swift/Syntax/Syntax.h +++ b/include/swift/Syntax/Syntax.h @@ -172,11 +172,11 @@ class Syntax { /// Returns the first non-missing token in this syntax. Returns None if there /// is no non-missing token. - Optional getFirstToken(); + Optional getFirstToken() const; /// Returns the last non-missing token in this syntax. Returns None if there /// is no non-missing token. - Optional getLastToken(); + Optional getLastToken() const; /// Print the syntax node with full fidelity to the given output stream. void print(llvm::raw_ostream &OS, SyntaxPrintOptions Opts = SyntaxPrintOptions()) const; diff --git a/include/swift/Syntax/SyntaxNodes.h.gyb b/include/swift/Syntax/SyntaxNodes.h.gyb index 0e4a9a9bf5d54..4d644890a9014 100644 --- a/include/swift/Syntax/SyntaxNodes.h.gyb +++ b/include/swift/Syntax/SyntaxNodes.h.gyb @@ -81,9 +81,9 @@ public: /// ${line} % end % if child.is_optional: - llvm::Optional<${child.type_name}> get${child.name}(); + llvm::Optional<${child.type_name}> get${child.name}() const; % else: - ${child.type_name} get${child.name}(); + ${child.type_name} get${child.name}() const; % end % child_node = NODE_MAP.get(child.syntax_kind) diff --git a/lib/Parse/ASTGen.cpp b/lib/Parse/ASTGen.cpp index 98546643c2712..67655eb8efc17 100644 --- a/lib/Parse/ASTGen.cpp +++ b/lib/Parse/ASTGen.cpp @@ -18,58 +18,64 @@ using namespace swift; using namespace swift::syntax; -SourceLoc ASTGen::generate(TokenSyntax Tok, SourceLoc &Loc) { +SourceLoc ASTGen::generate(const TokenSyntax &Tok, const SourceLoc Loc) { return advanceLocBegin(Loc, Tok); } -Expr *ASTGen::generate(IntegerLiteralExprSyntax &Expr, SourceLoc &Loc) { +Expr *ASTGen::generate(const IntegerLiteralExprSyntax &Expr, + const SourceLoc Loc) { auto Digits = Expr.getDigits(); auto Text = copyAndStripUnderscores(Digits.getText()); auto DigitsLoc = advanceLocBegin(Loc, Digits); return new (Context) IntegerLiteralExpr(Text, DigitsLoc); } -Expr *ASTGen::generate(FloatLiteralExprSyntax &Expr, SourceLoc &Loc) { +Expr *ASTGen::generate(const FloatLiteralExprSyntax &Expr, + const SourceLoc Loc) { auto Digits = Expr.getFloatingDigits(); auto Text = copyAndStripUnderscores(Digits.getText()); auto DigitsLoc = advanceLocBegin(Loc, Digits); return new (Context) FloatLiteralExpr(Text, DigitsLoc); } -Expr *ASTGen::generate(NilLiteralExprSyntax &Expr, SourceLoc &Loc) { +Expr *ASTGen::generate(const NilLiteralExprSyntax &Expr, const SourceLoc Loc) { auto Nil = Expr.getNilKeyword(); auto NilLoc = advanceLocBegin(Loc, Nil); return new (Context) NilLiteralExpr(NilLoc); } -Expr *ASTGen::generate(BooleanLiteralExprSyntax &Expr, SourceLoc &Loc) { +Expr *ASTGen::generate(const BooleanLiteralExprSyntax &Expr, + const SourceLoc Loc) { auto Boolean = Expr.getBooleanLiteral(); auto Value = Boolean.getTokenKind() == tok::kw_true; auto BooleanLoc = advanceLocBegin(Loc, Boolean); return new (Context) BooleanLiteralExpr(Value, BooleanLoc); } -Expr *ASTGen::generate(PoundFileExprSyntax &Expr, SourceLoc &Loc) { +Expr *ASTGen::generate(const PoundFileExprSyntax &Expr, const SourceLoc Loc) { return generateMagicIdentifierLiteralExpression(Expr.getPoundFile(), Loc); } -Expr *ASTGen::generate(PoundLineExprSyntax &Expr, SourceLoc &Loc) { +Expr *ASTGen::generate(const PoundLineExprSyntax &Expr, const SourceLoc Loc) { return generateMagicIdentifierLiteralExpression(Expr.getPoundLine(), Loc); } -Expr *ASTGen::generate(PoundColumnExprSyntax &Expr, SourceLoc &Loc) { +Expr *ASTGen::generate(const PoundColumnExprSyntax &Expr, const SourceLoc Loc) { return generateMagicIdentifierLiteralExpression(Expr.getPoundColumn(), Loc); } -Expr *ASTGen::generate(PoundFunctionExprSyntax &Expr, SourceLoc &Loc) { +Expr *ASTGen::generate(const PoundFunctionExprSyntax &Expr, + const SourceLoc Loc) { return generateMagicIdentifierLiteralExpression(Expr.getPoundFunction(), Loc); } -Expr *ASTGen::generate(PoundDsohandleExprSyntax &Expr, SourceLoc &Loc) { - return generateMagicIdentifierLiteralExpression(Expr.getPoundDsohandle(), Loc); +Expr *ASTGen::generate(const PoundDsohandleExprSyntax &Expr, + const SourceLoc Loc) { + return generateMagicIdentifierLiteralExpression(Expr.getPoundDsohandle(), + Loc); } -Expr *ASTGen::generate(UnknownExprSyntax &Expr, SourceLoc &Loc) { +Expr *ASTGen::generate(const UnknownExprSyntax &Expr, const SourceLoc Loc) { if (Expr.getNumChildren() == 1 && Expr.getChild(0)->isToken()) { Syntax Token = *Expr.getChild(0); tok Kind = Token.getRaw()->getTokenKind(); @@ -90,7 +96,7 @@ Expr *ASTGen::generate(UnknownExprSyntax &Expr, SourceLoc &Loc) { return nullptr; } -TypeRepr *ASTGen::generate(TypeSyntax Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const TypeSyntax &Type, const SourceLoc Loc) { TypeRepr *TypeAST = nullptr; if (auto SimpleIdentifier = Type.getAs()) @@ -128,7 +134,8 @@ TypeRepr *ASTGen::generate(TypeSyntax Type, SourceLoc &Loc) { return cacheType(Type, TypeAST); } -TypeRepr *ASTGen::generate(FunctionTypeSyntax Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const FunctionTypeSyntax &Type, + const SourceLoc Loc) { auto ArgumentTypes = generateTuple(Type.getLeftParen(), Type.getArguments(), Type.getRightParen(), Loc, /*IsFunction=*/true); @@ -144,10 +151,10 @@ TypeRepr *ASTGen::generate(FunctionTypeSyntax Type, SourceLoc &Loc) { FunctionTypeRepr(nullptr, ArgumentTypes, ThrowsLoc, ArrowLoc, ReturnType); } -TupleTypeRepr *ASTGen::generateTuple(TokenSyntax LParen, - TupleTypeElementListSyntax Elements, - TokenSyntax RParen, SourceLoc &Loc, - bool IsFunction) { +TupleTypeRepr *ASTGen::generateTuple(const TokenSyntax &LParen, + const TupleTypeElementListSyntax &Elements, + const TokenSyntax &RParen, + const SourceLoc Loc, bool IsFunction) { auto LPLoc = generate(LParen, Loc); auto RPLoc = generate(RParen, Loc); @@ -204,7 +211,8 @@ TupleTypeRepr *ASTGen::generateTuple(TokenSyntax LParen, EllipsisLoc, EllipsisIdx); } -TypeRepr *ASTGen::generate(AttributedTypeSyntax Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const AttributedTypeSyntax &Type, + const SourceLoc Loc) { // todo [gsoc]: improve this after refactoring attribute parsing auto TypeAST = generate(Type.getBaseType(), Loc); @@ -260,19 +268,20 @@ TypeRepr *ASTGen::generate(AttributedTypeSyntax Type, SourceLoc &Loc) { return TypeAST; } -TypeRepr *ASTGen::generate(TupleTypeSyntax Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const TupleTypeSyntax &Type, const SourceLoc Loc) { return generateTuple(Type.getLeftParen(), Type.getElements(), Type.getRightParen(), Loc); } -TypeRepr *ASTGen::generate(SomeTypeSyntax Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const SomeTypeSyntax &Type, const SourceLoc Loc) { auto Some = Type.getSomeSpecifier(); auto SomeLoc = generate(Some, Loc); auto BaseType = generate(Type.getBaseType(), Loc); return new (Context) OpaqueReturnTypeRepr(SomeLoc, BaseType); } -TypeRepr *ASTGen::generate(CompositionTypeSyntax Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const CompositionTypeSyntax &Type, + const SourceLoc Loc) { auto Elements = Type.getElements(); auto FirstElem = Elements[0]; auto LastElem = Elements[Elements.size() - 1]; @@ -309,7 +318,7 @@ TypeRepr *ASTGen::generate(CompositionTypeSyntax Type, SourceLoc &Loc) { } void ASTGen::gatherTypeIdentifierComponents( - TypeSyntax Component, SourceLoc &Loc, + const TypeSyntax &Component, const SourceLoc Loc, SmallVectorImpl &Components) { if (auto SimpleIdentifier = Component.getAs()) { auto ComponentType = generateIdentifier(*SimpleIdentifier, Loc); @@ -329,7 +338,8 @@ void ASTGen::gatherTypeIdentifierComponents( } template -TypeRepr *ASTGen::generateSimpleOrMemberIdentifier(T Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generateSimpleOrMemberIdentifier(const T &Type, + const SourceLoc Loc) { SmallVector Components; gatherTypeIdentifierComponents(Type, Loc, Components); std::reverse(Components.begin(), Components.end()); @@ -347,7 +357,8 @@ TypeRepr *ASTGen::generateSimpleOrMemberIdentifier(T Type, SourceLoc &Loc) { } template -ComponentIdentTypeRepr *ASTGen::generateIdentifier(T Type, SourceLoc &Loc) { +ComponentIdentTypeRepr *ASTGen::generateIdentifier(const T &Type, + const SourceLoc Loc) { auto IdentifierLoc = advanceLocBegin(Loc, Type.getName()); auto Identifier = Context.getIdentifier(Type.getName().getIdentifierText()); if (auto Clause = Type.getGenericArgumentClause()) { @@ -364,25 +375,28 @@ ComponentIdentTypeRepr *ASTGen::generateIdentifier(T Type, SourceLoc &Loc) { return new (Context) SimpleIdentTypeRepr(IdentifierLoc, Identifier); } -TypeRepr *ASTGen::generate(SimpleTypeIdentifierSyntax Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const SimpleTypeIdentifierSyntax &Type, + const SourceLoc Loc) { if (Type.getName().getTokenKind() == tok::kw_Any) { auto AnyLoc = advanceLocBegin(Loc, Type.getName()); return CompositionTypeRepr::createEmptyComposition(Context, AnyLoc); } if (Type.getName().getText() == "class") { auto classLoc = advanceLocBegin(Loc, Type.getName()); - return new (Context) SimpleIdentTypeRepr(classLoc, - Context.getIdentifier("AnyObject")); + return new (Context) + SimpleIdentTypeRepr(classLoc, Context.getIdentifier("AnyObject")); } return generateSimpleOrMemberIdentifier(Type, Loc); } -TypeRepr *ASTGen::generate(MemberTypeIdentifierSyntax Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const MemberTypeIdentifierSyntax &Type, + SourceLoc Loc) { return generateSimpleOrMemberIdentifier(Type, Loc); } -TypeRepr *ASTGen::generate(DictionaryTypeSyntax Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const DictionaryTypeSyntax &Type, + const SourceLoc Loc) { TypeRepr *ValueType = generate(Type.getValueType(), Loc); TypeRepr *KeyType = generate(Type.getKeyType(), Loc); auto LBraceLoc = advanceLocBegin(Loc, Type.getLeftSquareBracket()); @@ -392,7 +406,7 @@ TypeRepr *ASTGen::generate(DictionaryTypeSyntax Type, SourceLoc &Loc) { return new (Context) DictionaryTypeRepr(KeyType, ValueType, ColonLoc, Range); } -TypeRepr *ASTGen::generate(ArrayTypeSyntax Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const ArrayTypeSyntax &Type, SourceLoc Loc) { TypeRepr *ElementType = generate(Type.getElementType(), Loc); SourceLoc LBraceLoc, RBraceLoc; if (Type.getLeftSquareBracket().isPresent()) @@ -406,7 +420,8 @@ TypeRepr *ASTGen::generate(ArrayTypeSyntax Type, SourceLoc &Loc) { return new (Context) ArrayTypeRepr(ElementType, {LBraceLoc, RBraceLoc}); } -TypeRepr *ASTGen::generate(MetatypeTypeSyntax Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const MetatypeTypeSyntax &Type, + const SourceLoc Loc) { TypeRepr *BaseType = generate(Type.getBaseType(), Loc); auto TypeOrProtocol = Type.getTypeOrProtocol(); auto TypeOrProtocolLoc = advanceLocBegin(Loc, TypeOrProtocol); @@ -415,21 +430,22 @@ TypeRepr *ASTGen::generate(MetatypeTypeSyntax Type, SourceLoc &Loc) { return new (Context) ProtocolTypeRepr(BaseType, TypeOrProtocolLoc); } -TypeRepr *ASTGen::generate(OptionalTypeSyntax Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const OptionalTypeSyntax &Type, + const SourceLoc Loc) { TypeRepr *WrappedType = generate(Type.getWrappedType(), Loc); auto QuestionLoc = advanceLocBegin(Loc, Type.getQuestionMark()); return new (Context) OptionalTypeRepr(WrappedType, QuestionLoc); } -TypeRepr *ASTGen::generate(ImplicitlyUnwrappedOptionalTypeSyntax Type, - SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const ImplicitlyUnwrappedOptionalTypeSyntax &Type, + const SourceLoc Loc) { TypeRepr *WrappedType = generate(Type.getWrappedType(), Loc); auto ExclamationLoc = advanceLocBegin(Loc, Type.getExclamationMark()); return new (Context) ImplicitlyUnwrappedOptionalTypeRepr(WrappedType, ExclamationLoc); } -TypeRepr *ASTGen::generate(UnknownTypeSyntax Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const UnknownTypeSyntax &Type, const SourceLoc Loc) { auto ChildrenCount = Type.getNumChildren(); // Recover from old-style protocol composition: @@ -475,7 +491,8 @@ TypeRepr *ASTGen::generate(UnknownTypeSyntax Type, SourceLoc &Loc) { auto LParen = Type.getChild(0)->getAs(); if (LParen && LParen->getTokenKind() == tok::l_paren) { auto LParenLoc = advanceLocBegin(Loc, *LParen); - auto EndLoc = advanceLocBegin(Loc, *Type.getChild(Type.getNumChildren() - 1)); + auto EndLoc = + advanceLocBegin(Loc, *Type.getChild(Type.getNumChildren() - 1)); return TupleTypeRepr::createEmpty(Context, {LParenLoc, EndLoc}); } } @@ -484,8 +501,8 @@ TypeRepr *ASTGen::generate(UnknownTypeSyntax Type, SourceLoc &Loc) { return nullptr; } -SmallVector ASTGen::generate(GenericArgumentListSyntax Args, - SourceLoc &Loc) { +SmallVector +ASTGen::generate(const GenericArgumentListSyntax &Args, const SourceLoc Loc) { SmallVector Types; Types.resize(Args.size()); @@ -498,7 +515,8 @@ SmallVector ASTGen::generate(GenericArgumentListSyntax Args, return Types; } -TypeRepr *ASTGen::generate(GenericArgumentSyntax Arg, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const GenericArgumentSyntax &Arg, + const SourceLoc Loc) { return generate(Arg.getArgumentType(), Loc); } @@ -517,8 +535,9 @@ StringRef ASTGen::copyAndStripUnderscores(StringRef Orig, ASTContext &Context) { return StringRef(start, p - start); } -GenericParamList *ASTGen::generate(GenericParameterClauseListSyntax clauses, - SourceLoc &Loc) { +GenericParamList * +ASTGen::generate(const GenericParameterClauseListSyntax &clauses, + const SourceLoc Loc) { GenericParamList *curr = nullptr; // The first one is the outmost generic parameter list. @@ -533,8 +552,8 @@ GenericParamList *ASTGen::generate(GenericParameterClauseListSyntax clauses, return curr; } -GenericParamList *ASTGen::generate(GenericParameterClauseSyntax clause, - SourceLoc &Loc) { +GenericParamList *ASTGen::generate(const GenericParameterClauseSyntax &clause, + const SourceLoc Loc) { SmallVector params; params.reserve(clause.getGenericParameterList().getNumChildren()); @@ -593,8 +612,9 @@ GenericParamList *ASTGen::generate(GenericParameterClauseSyntax clause, requirements, rAngleLoc); } -Optional ASTGen::generate(syntax::GenericRequirementSyntax req, - SourceLoc &Loc) { +Optional +ASTGen::generate(const syntax::GenericRequirementSyntax &req, + const SourceLoc Loc) { if (auto sameTypeReq = req.getBody().getAs()) { auto firstType = generate(sameTypeReq->getLeftTypeIdentifier(), Loc); auto secondType = generate(sameTypeReq->getRightTypeIdentifier(), Loc); @@ -643,8 +663,8 @@ static LayoutConstraintKind getLayoutConstraintKind(Identifier &id, return LayoutConstraintKind::UnknownLayout; } -LayoutConstraint ASTGen::generate(LayoutConstraintSyntax constraint, - SourceLoc &Loc) { +LayoutConstraint ASTGen::generate(const LayoutConstraintSyntax &constraint, + const SourceLoc Loc) { auto name = Context.getIdentifier(constraint.getName().getIdentifierText()); auto constraintKind = getLayoutConstraintKind(name, Context); assert(constraintKind != LayoutConstraintKind::UnknownLayout); @@ -681,14 +701,16 @@ StringRef ASTGen::copyAndStripUnderscores(StringRef Orig) { return copyAndStripUnderscores(Orig, Context); } -Expr *ASTGen::generateMagicIdentifierLiteralExpression(TokenSyntax PoundToken, - SourceLoc &Loc) { +Expr * +ASTGen::generateMagicIdentifierLiteralExpression(const TokenSyntax &PoundToken, + const SourceLoc Loc) { auto Kind = getMagicIdentifierLiteralKind(PoundToken.getTokenKind()); auto KindLoc = advanceLocBegin(Loc, PoundToken); return new (Context) MagicIdentifierLiteralExpr(Kind, KindLoc); } -MagicIdentifierLiteralExpr::Kind ASTGen::getMagicIdentifierLiteralKind(tok Kind) { +MagicIdentifierLiteralExpr::Kind +ASTGen::getMagicIdentifierLiteralKind(tok Kind) { switch (Kind) { case tok::kw___COLUMN__: case tok::pound_column: @@ -728,15 +750,15 @@ TypeRepr *ASTGen::lookupType(TypeSyntax Type) { return Found != TypeCache.end() ? Found->second : nullptr; } -TypeRepr *ASTGen::addType(TypeRepr *Type, const SourceLoc &Loc) { - return Types.insert({Loc, Type}).first->second; +void ASTGen::addType(TypeRepr *Type, const SourceLoc Loc) { + Types.insert({Loc, Type}); } -bool ASTGen::hasType(const SourceLoc &Loc) const { +bool ASTGen::hasType(const SourceLoc Loc) const { return Types.find(Loc) != Types.end(); } -TypeRepr *ASTGen::getType(const SourceLoc &Loc) const { +TypeRepr *ASTGen::getType(const SourceLoc Loc) const { return Types.find(Loc)->second; } diff --git a/lib/Syntax/Syntax.cpp b/lib/Syntax/Syntax.cpp index 38d08ff4da8de..57aa313597c7b 100644 --- a/lib/Syntax/Syntax.cpp +++ b/lib/Syntax/Syntax.cpp @@ -98,13 +98,13 @@ llvm::Optional Syntax::getChild(const size_t N) const { return Syntax {Root, ChildData.get()}; } -Optional Syntax::getFirstToken() { +Optional Syntax::getFirstToken() const { if (auto tok = getData().getFirstToken()) return TokenSyntax(Root, tok.get()); return None; } -Optional Syntax::getLastToken() { +Optional Syntax::getLastToken() const { if (auto tok = getData().getLastToken()) return TokenSyntax(Root, tok.get()); return None; diff --git a/lib/Syntax/SyntaxNodes.cpp.gyb b/lib/Syntax/SyntaxNodes.cpp.gyb index e3302f3389914..411d3918738fb 100644 --- a/lib/Syntax/SyntaxNodes.cpp.gyb +++ b/lib/Syntax/SyntaxNodes.cpp.gyb @@ -55,14 +55,14 @@ void ${node.name}::validate() const { % for child in node.children: % if child.is_optional: -llvm::Optional<${child.type_name}> ${node.name}::get${child.name}() { +llvm::Optional<${child.type_name}> ${node.name}::get${child.name}() const { auto ChildData = Data->getChild(Cursor::${child.name}); if (!ChildData) return llvm::None; return ${child.type_name} {Root, ChildData.get()}; } % else: -${child.type_name} ${node.name}::get${child.name}() { +${child.type_name} ${node.name}::get${child.name}() const { return ${child.type_name} {Root, Data->getChild(Cursor::${child.name}).get()}; } % end From 3bbc50430bc18579c5fcbbc4f5d0321df14b3fdb Mon Sep 17 00:00:00 2001 From: Dan Zheng Date: Sat, 21 Sep 2019 04:38:25 -0700 Subject: [PATCH 138/199] Add `-no-toolchain-stdlib-rpath` flag. (#27207) Add `-no-toolchain-stdlib-rpath` flag: the negative version of `-toolchain-stdlib-rpath`. Make `-no-toolchain-stdlib-rpath` be the default: use `/usr/lib/swift` as default RPATH on Darwin platforms instead of toolchain standard library. Adapted from https://github.com/apple/swift/pull/27206. tensorflow branch requires the opposite default (use toolchain standard library as RPATH) because some stdlib modules like TensorFlow do not exist in `/usr/lib/swift`. --- include/swift/Option/Options.td | 3 +++ lib/Driver/DarwinToolChains.cpp | 3 ++- test/Driver/linker-rpath.swift | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index 24d2d4c08e68c..09579e748c903 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -508,6 +508,9 @@ def no_static_stdlib: Flag<["-"], "no-static-stdlib">, def toolchain_stdlib_rpath: Flag<["-"], "toolchain-stdlib-rpath">, Flags<[HelpHidden,DoesNotAffectIncrementalBuild]>, HelpText<"Add an rpath entry for the toolchain's standard library, rather than the OS's">; +def no_toolchain_stdlib_rpath: Flag<["-"], "no-toolchain-stdlib-rpath">, + Flags<[HelpHidden,DoesNotAffectIncrementalBuild]>, + HelpText<"Do not add an rpath entry for the toolchain's standard library (default)">; def no_stdlib_rpath: Flag<["-"], "no-stdlib-rpath">, Flags<[HelpHidden,DoesNotAffectIncrementalBuild]>, HelpText<"Don't add any rpath entries.">; diff --git a/lib/Driver/DarwinToolChains.cpp b/lib/Driver/DarwinToolChains.cpp index 2a1efaaa1645c..abb8a389c0a06 100644 --- a/lib/Driver/DarwinToolChains.cpp +++ b/lib/Driver/DarwinToolChains.cpp @@ -389,7 +389,8 @@ toolchains::Darwin::addArgsToLinkStdlib(ArgStringList &Arguments, Arguments.push_back(context.Args.MakeArgString(path)); } - if (context.Args.hasArg(options::OPT_toolchain_stdlib_rpath)) { + if (context.Args.hasFlag(options::OPT_toolchain_stdlib_rpath, + options::OPT_no_toolchain_stdlib_rpath, false)) { // If the user has explicitly asked for a toolchain stdlib, we should // provide one using -rpath. This used to be the default behaviour but it // was considered annoying in at least the SwiftPM scenario (see diff --git a/test/Driver/linker-rpath.swift b/test/Driver/linker-rpath.swift index 82b0dca4d17d5..1167e20465e6b 100644 --- a/test/Driver/linker-rpath.swift +++ b/test/Driver/linker-rpath.swift @@ -37,6 +37,10 @@ // RUN: %swiftc_driver_plain -driver-print-jobs -toolchain-stdlib-rpath -target x86_64-apple-macosx10.9 %S/../Inputs/empty.swift -resource-dir garbage/ | %FileCheck -check-prefix TOOLCHAIN-RPATH -DPLATFORM=%target-sdk-name %s // RUN: %swiftc_driver_plain -driver-print-jobs -toolchain-stdlib-rpath -target x86_64-apple-macosx10.15 %S/../Inputs/empty.swift -resource-dir garbage/ | %FileCheck -check-prefix TOOLCHAIN-RPATH -DPLATFORM=%target-sdk-name %s +// ### Test with -no-toolchain-stdlib-rpath +// RUN: %swiftc_driver_plain -driver-print-jobs -no-toolchain-stdlib-rpath -target x86_64-apple-macosx10.9 %S/../Inputs/empty.swift | %FileCheck -check-prefix RPATH %s +// RUN: %swiftc_driver_plain -driver-print-jobs -no-toolchain-stdlib-rpath -target x86_64-apple-macosx10.15 %S/../Inputs/empty.swift | %FileCheck -check-prefix NO-RPATH %s + // TOOLCHAIN-RPATH: bin/ld{{"? }} // TOOLCHAIN-RPATH-SAME: -rpath garbage/[[PLATFORM]]{{ }} // TOOLCHAIN-RPATH-SAME: -o {{[^ ]+}} From aad82fd9c5e63957785bcbc42af4db32a7e87c4d Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 21 Sep 2019 09:53:08 -0700 Subject: [PATCH 139/199] [NFC] Remove unnecessary validation noise Drop some callers to validateDecl and resolveDeclSignature that did not actually need the interface type. --- lib/AST/ConformanceLookupTable.cpp | 10 ---------- lib/IRGen/GenProto.cpp | 5 ----- lib/Sema/CodeSynthesis.cpp | 5 ----- lib/Sema/TypeCheckProtocol.cpp | 6 +----- lib/Sema/TypeCheckProtocolInference.cpp | 5 ----- 5 files changed, 1 insertion(+), 30 deletions(-) diff --git a/lib/AST/ConformanceLookupTable.cpp b/lib/AST/ConformanceLookupTable.cpp index 0e48505ff16c0..dbe519d83907a 100644 --- a/lib/AST/ConformanceLookupTable.cpp +++ b/lib/AST/ConformanceLookupTable.cpp @@ -795,16 +795,6 @@ ConformanceLookupTable::getConformance(NominalTypeDecl *nominal, if (!conformingDC) return nullptr; - // Everything about this conformance is nailed down, so we can now ensure that - // the extension is fully resolved. - if (auto resolver = nominal->getASTContext().getLazyResolver()) { - if (auto ext = dyn_cast(conformingDC)) { - resolver->resolveDeclSignature(ext->getExtendedNominal()); - } else { - resolver->resolveDeclSignature(cast(conformingDC)); - } - } - auto *conformingNominal = conformingDC->getSelfNominalTypeDecl(); // Form the conformance. diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp index 3b1bbfb0ee734..92b75b40234b5 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -2959,11 +2959,6 @@ NecessaryBindings::forFunctionInvocations(IRGenModule &IGM, GenericTypeRequirements::GenericTypeRequirements(IRGenModule &IGM, NominalTypeDecl *typeDecl) : TheDecl(typeDecl) { - - // FIXME: Remove this once getGenericSignature() is a request. - if (!typeDecl->hasInterfaceType()) - IGM.Context.getLazyResolver()->resolveDeclSignature(typeDecl); - // We only need to do something here if the declaration context is // somehow generic. auto ncGenerics = typeDecl->getGenericSignatureOfContext(); diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index a55232dfa4de2..078d896fef45f 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -1079,11 +1079,6 @@ static void addImplicitConstructorsToClass(ClassDecl *decl, ASTContext &ctx) { ? DesignatedInitKind::Chaining : DesignatedInitKind::Stub; - // We have a designated initializer. Create an override of it. - // FIXME: Validation makes sure we get a generic signature here. - if (!decl->hasInterfaceType()) - ctx.getLazyResolver()->resolveDeclSignature(decl); - if (auto ctor = createDesignatedInitOverride( decl, superclassCtor, kind, ctx)) { decl->addMember(ctor); diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 5071d2dd3e83e..b8c15973146f6 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -2205,11 +2205,7 @@ ConformanceChecker::ConformanceChecker( Conformance(conformance), Loc(conformance->getLoc()), GlobalMissingWitnesses(GlobalMissingWitnesses), LocalMissingWitnessesStartIndex(GlobalMissingWitnesses.size()), - SuppressDiagnostics(suppressDiagnostics) { - // The protocol may have only been validatedDeclForNameLookup'd until - // here, so fill in any information that's missing. - tc.validateDecl(conformance->getProtocol()); -} + SuppressDiagnostics(suppressDiagnostics) { } ArrayRef ConformanceChecker::getReferencedAssociatedTypes(ValueDecl *req) { diff --git a/lib/Sema/TypeCheckProtocolInference.cpp b/lib/Sema/TypeCheckProtocolInference.cpp index afdfa51b50e98..91a8b680f7d62 100644 --- a/lib/Sema/TypeCheckProtocolInference.cpp +++ b/lib/Sema/TypeCheckProtocolInference.cpp @@ -189,11 +189,6 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses( if (extendedNominal == nullptr) return true; - // Validate the nominal type being extended. - tc.validateDecl(extendedNominal); - if (extendedNominal->isInvalid()) - return true; - // Assume unconstrained concrete extensions we found witnesses in are // always viable. if (!isa(extendedNominal)) From 7736009f92827a2ccb5edca39556c5bb86ecd349 Mon Sep 17 00:00:00 2001 From: David Ungar Date: Wed, 18 Sep 2019 11:17:39 -0700 Subject: [PATCH 140/199] Fix debug code --- lib/AST/UnqualifiedLookup.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/AST/UnqualifiedLookup.cpp b/lib/AST/UnqualifiedLookup.cpp index d8bd21798f606..2f8841e031437 100644 --- a/lib/AST/UnqualifiedLookup.cpp +++ b/lib/AST/UnqualifiedLookup.cpp @@ -472,7 +472,7 @@ UnqualifiedLookupFactory::UnqualifiedLookupFactory( void UnqualifiedLookupFactory::performUnqualifiedLookup() { #ifndef NDEBUG ++lookupCounter; - stopForDebuggingIfStartingTargetLookup(false); + auto localCounter = lookupCounter; #endif FrontendStatsTracer StatsTracer(Ctx.Stats, "performUnqualifedLookup", DC->getParentSourceFile()); @@ -492,6 +492,10 @@ void UnqualifiedLookupFactory::performUnqualifiedLookup() { return; } +#ifndef NDEBUG + stopForDebuggingIfStartingTargetLookup(false); +#endif + if (Name.isOperator()) lookupOperatorInDeclContexts(contextAndIsCascadingUse); else From 603cc05289a30c4af40fe3d03b94add172e678ee Mon Sep 17 00:00:00 2001 From: David Ungar Date: Wed, 18 Sep 2019 22:46:42 -0700 Subject: [PATCH 141/199] WIP lazy whole scopes --- include/swift/AST/ASTScope.h | 36 +++++++++++++++++++++++++++++---- lib/AST/ASTScopeCreation.cpp | 33 ++++++++++++++++++++++++++---- lib/AST/ASTScopeLookup.cpp | 12 +++++++++-- lib/AST/ASTScopeSourceRange.cpp | 30 ++++++++++++++++----------- 4 files changed, 89 insertions(+), 22 deletions(-) diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index 50b37036bf42a..84ca280eedd01 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -585,12 +585,12 @@ class Portion { virtual const Decl * getReferrentOfScope(const GenericTypeOrExtensionScope *s) const; - virtual void beCurrent(IterableTypeScope *) const; - virtual bool isCurrent(const IterableTypeScope *) const; + virtual void beCurrent(IterableTypeScope *) const = 0; + virtual bool isCurrent(const IterableTypeScope *) const = 0; virtual NullablePtr - insertionPointForDeferredExpansion(IterableTypeScope *) const; + insertionPointForDeferredExpansion(IterableTypeScope *) const = 0; virtual SourceRange - sourceRangeForDeferredExpansion(const IterableTypeScope *) const; + sourceRangeForDeferredExpansion(const IterableTypeScope *) const = 0; }; // For the whole Decl scope of a GenericType or an Extension @@ -611,6 +611,24 @@ class Portion { const Decl * getReferrentOfScope(const GenericTypeOrExtensionScope *s) const override; + + /// Make whole portion lazy to avoid circularity in lookup of generic + /// parameters of extensions. When \c bindExtension is called, it needs to + /// unqualifed-lookup the type being extended. That causes an \c + /// ExtensionScope + /// (\c GenericTypeOrExtensionWholePortion) to be built. + /// The building process needs the generic parameters, but that results in a + /// request for the extended nominal type of the \c ExtensionDecl, which is + /// an endless recursion. Although we only need to make \c ExtensionScope + /// lazy, might as well do it for all \c IterableTypeScopes. + + void beCurrent(IterableTypeScope *) const override; + bool isCurrent(const IterableTypeScope *) const override; + + NullablePtr + insertionPointForDeferredExpansion(IterableTypeScope *) const override; + SourceRange + sourceRangeForDeferredExpansion(const IterableTypeScope *) const override; }; /// GenericTypeOrExtension = GenericType or Extension @@ -649,6 +667,14 @@ class GenericTypeOrExtensionWherePortion final SourceRange getChildlessSourceRangeOf(const GenericTypeOrExtensionScope *, bool omitAssertions) const override; + + void beCurrent(IterableTypeScope *) const override; + bool isCurrent(const IterableTypeScope *) const override; + + NullablePtr + insertionPointForDeferredExpansion(IterableTypeScope *) const override; + SourceRange + sourceRangeForDeferredExpansion(const IterableTypeScope *) const override; }; /// Behavior specific to representing the Body of a NominalTypeDecl or @@ -766,6 +792,8 @@ class IterableTypeScope : public GenericTypeScope { bool isCurrent() const override; public: + void makeWholeCurrent(); + bool isWholeCurrent() const; void makeBodyCurrent(); bool isBodyCurrent() const; NullablePtr insertionPointForDeferredExpansion() override; diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index ad7b2f43169ba..fc147fa851add 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -1811,8 +1811,15 @@ NullablePtr IterableTypeScope::insertionPointForDeferredExpansion() { return portion->insertionPointForDeferredExpansion(this); } + +NullablePtr +GenericTypeOrExtensionWholePortion::insertionPointForDeferredExpansion( + IterableTypeScope *s) const { + return s->getParent().get(); +} NullablePtr -Portion::insertionPointForDeferredExpansion(IterableTypeScope *) const { +GenericTypeOrExtensionWherePortion::insertionPointForDeferredExpansion( + IterableTypeScope *) const { return nullptr; } NullablePtr @@ -1828,9 +1835,18 @@ bool ASTScopeImpl::isCurrent() const { return true; } void IterableTypeScope::beCurrent() { portion->beCurrent(this); } bool IterableTypeScope::isCurrent() const { return portion->isCurrent(this); } -void Portion::beCurrent(IterableTypeScope *) const {} -bool Portion::isCurrent(const IterableTypeScope *) const { return true; } - +void GenericTypeOrExtensionWholePortion::beCurrent(IterableTypeScope *s) const { + s->makeWholeCurrent(); +} +bool GenericTypeOrExtensionWholePortion::isCurrent( + const IterableTypeScope *s) const { + return s->isWholeCurrent(); +} +void GenericTypeOrExtensionWherePortion::beCurrent(IterableTypeScope *) const {} +bool GenericTypeOrExtensionWherePortion::isCurrent( + const IterableTypeScope *) const { + return true; +} void IterableTypeBodyPortion::beCurrent(IterableTypeScope *s) const { s->makeBodyCurrent(); } @@ -1838,6 +1854,15 @@ bool IterableTypeBodyPortion::isCurrent(const IterableTypeScope *s) const { return s->isBodyCurrent(); } +void IterableTypeScope::makeWholeCurrent() { + ASTScopeAssert(!shouldHaveABody() || !getChildren().empty(), + "Should have been expanded"); +} +bool IterableTypeScope::isWholeCurrent() const { + // Whole starts out unexpanded, and is lazily built but will have at least a + // body scope child + return !getChildren().empty(); +} void IterableTypeScope::makeBodyCurrent() { memberCount = getIterableDeclContext().get()->getMemberCount(); } diff --git a/lib/AST/ASTScopeLookup.cpp b/lib/AST/ASTScopeLookup.cpp index 84dc649250e66..f62ae897c6bb5 100644 --- a/lib/AST/ASTScopeLookup.cpp +++ b/lib/AST/ASTScopeLookup.cpp @@ -62,6 +62,14 @@ const ASTScopeImpl *ASTScopeImpl::findStartingScopeForLookup( if (name.isOperator()) return fileScope; // operators always at file scope + { + const SourceManager &SM = fileScope->getSourceManager(); + if (SM.getLineAndColumn(loc) == + std::make_pair(271, 38) && + SM.getIdentifierForBuffer(SM.findBufferContainingLoc(loc)) + .endswith("CompilerProtocols.swift")) + llvm::errs() << "HERE\n"; + } const auto innermost = fileScope->findInnermostEnclosingScope(loc, nullptr); // The legacy lookup code gets passed both a SourceLoc and a starting context. @@ -94,8 +102,8 @@ const ASTScopeImpl *ASTScopeImpl::findStartingScopeForLookup( // fileScope->dump(); llvm::errs() << "\n\n"; - ASTScopeAssert(fileScope->crossCheckWithAST(), - "Tree creation missed some DeclContexts."); + if (fileScope->crossCheckWithAST()) + llvm::errs() << "Tree creation missed some DeclContexts.\n"; } ASTScopeAssert(startingScope, "ASTScopeImpl: could not find startingScope"); diff --git a/lib/AST/ASTScopeSourceRange.cpp b/lib/AST/ASTScopeSourceRange.cpp index 685b85fd1b546..2936d8858ff7f 100644 --- a/lib/AST/ASTScopeSourceRange.cpp +++ b/lib/AST/ASTScopeSourceRange.cpp @@ -591,11 +591,27 @@ SourceRange AbstractFunctionBodyScope::sourceRangeForDeferredExpansion() const { return SourceRange(bsr.Start, endEvenIfNoCloseBraceAndEndsWithInterpolatedStringLiteral); } -SourceRange -Portion::sourceRangeForDeferredExpansion(const IterableTypeScope *) const { + +SourceRange GenericTypeOrExtensionWholePortion::sourceRangeForDeferredExpansion( + const IterableTypeScope *s) const { + const auto range = getChildlessSourceRangeOf(s, false); + return SourceRange(range.Start, getLocEncompassingPotentialLookups( + s->getSourceManager(), range.End)); +} + +SourceRange GenericTypeOrExtensionWherePortion::sourceRangeForDeferredExpansion( + const IterableTypeScope *) const { return SourceRange(); } +SourceRange IterableTypeBodyPortion::sourceRangeForDeferredExpansion( + const IterableTypeScope *s) const { + const auto bracesRange = getChildlessSourceRangeOf(s, false); + return SourceRange(bracesRange.Start, + getLocEncompassingPotentialLookups(s->getSourceManager(), + bracesRange.End)); +} + SourceRange ASTScopeImpl::getEffectiveSourceRange(const ASTNode n) const { if (const auto *d = n.dyn_cast()) return d->getSourceRange(); @@ -698,13 +714,3 @@ AbstractFunctionDeclScope::getParmsSourceLocOfAFD(AbstractFunctionDecl *decl) { : fd->getParameters()->getLParenLoc(); // clang-format on } - -#pragma mark deferred scope source ranges - -SourceRange IterableTypeBodyPortion::sourceRangeForDeferredExpansion( - const IterableTypeScope *s) const { - const auto bracesRange = getChildlessSourceRangeOf(s, false); - const auto &SM = s->getSourceManager(); - return SourceRange(bracesRange.Start, - getLocEncompassingPotentialLookups(SM, bracesRange.End)); -} From 37b16e8b330e4aebceaf2d666edb868ebdca1483 Mon Sep 17 00:00:00 2001 From: David Ungar Date: Thu, 19 Sep 2019 14:10:31 -0700 Subject: [PATCH 142/199] Tag cycles w/ radar --- include/swift/AST/ASTScope.h | 2 ++ lib/AST/ASTScopeCreation.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index 84ca280eedd01..17257c36c6504 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -1114,6 +1114,8 @@ class AttachedPropertyWrapperScope final : public ASTScopeImpl { /// false positives, that that doesn't hurt anything. However, the result of /// the conservative source range computation doesn't seem to be stable. So /// keep the original here, and use it for source range queries. + /// rdar://55263708 + const SourceRange sourceRangeWhenCreated; AttachedPropertyWrapperScope(VarDecl *e) diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index fc147fa851add..0749d93d711d8 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -388,6 +388,7 @@ class ScopeCreator final { // A safe way to discover this, without creating a circular request. // Cannot call getAttachedPropertyWrappers. + // rdar://55263708 static bool hasAttachedPropertyWrapper(VarDecl *vd) { return AttachedPropertyWrapperScope::getSourceRangeOfVarDecl(vd).isValid(); } From f33c4407dc6c55b24d697377edf8b6fcaa7049a8 Mon Sep 17 00:00:00 2001 From: David Ungar Date: Thu, 19 Sep 2019 14:58:47 -0700 Subject: [PATCH 143/199] Push range of extension scope after type, WIP --- include/swift/AST/ASTScope.h | 18 +++++++++++ lib/AST/ASTScopeSourceRange.cpp | 56 +++++++++++++++++++++++++++------ 2 files changed, 64 insertions(+), 10 deletions(-) diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index 17257c36c6504..f76f409844538 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -263,6 +263,8 @@ class ASTScopeImpl { void ensureSourceRangesAreCorrectWhenAddingDescendants(function_ref); public: // public for debugging + /// Returns source range of this node alone, without factoring in any + /// children. virtual SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const = 0; @@ -338,6 +340,8 @@ class ASTScopeImpl { /// Some scopes can be expanded lazily. /// Such scopes must: not change their source ranges after expansion, and /// their expansion must return an insertion point outside themselves. + /// After a node is expanded, its source range (getSourceRangeofThisASTNode + /// union children's ranges) must be same as this. virtual NullablePtr insertionPointForDeferredExpansion(); virtual SourceRange sourceRangeForDeferredExpansion() const; @@ -730,6 +734,17 @@ class GenericTypeOrExtensionScope : public ASTScopeImpl { SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; + /// \c tryBindExtension needs to get the extended nominal, and the DeclContext + /// is the parent of the \c ExtensionDecl. If the \c SourceRange of an \c + /// ExtensionScope were to start where the \c ExtensionDecl says, the lookup + /// source locaiton would fall within the \c ExtensionScope. This inclusion + /// would cause the lazy \c ExtensionScope to be expanded which would ask for + /// its generic parameters in order to create those sub-scopes. That request + /// would cause a cycle because it would ask for the extended nominal. So, + /// move the source range of an \c ExtensionScope *past* the extended nominal + /// type, which is not in-scope there anyway. + virtual SourceRange moveStartPastExtendedNominal(SourceRange) const = 0; + virtual GenericContext *getGenericContext() const = 0; std::string getClassName() const override; virtual std::string declKindName() const = 0; @@ -768,6 +783,8 @@ class GenericTypeScope : public GenericTypeOrExtensionScope { public: GenericTypeScope(const Portion *p) : GenericTypeOrExtensionScope(p) {} virtual ~GenericTypeScope() {} + SourceRange moveStartPastExtendedNominal(SourceRange) const override; + protected: NullablePtr genericParams() const override; }; @@ -842,6 +859,7 @@ class ExtensionScope final : public IterableTypeScope { NullablePtr getCorrespondingNominalTypeDecl() const override; std::string declKindName() const override { return "Extension"; } SourceRange getBraces() const override; + SourceRange moveStartPastExtendedNominal(SourceRange) const override; ASTScopeImpl *createTrailingWhereClauseScope(ASTScopeImpl *parent, ScopeCreator &) override; void createBodyScope(ASTScopeImpl *leaf, ScopeCreator &) override; diff --git a/lib/AST/ASTScopeSourceRange.cpp b/lib/AST/ASTScopeSourceRange.cpp index 2936d8858ff7f..afa0cf23bf45a 100644 --- a/lib/AST/ASTScopeSourceRange.cpp +++ b/lib/AST/ASTScopeSourceRange.cpp @@ -37,6 +37,7 @@ using namespace ast_scope; static SourceLoc getStartOfFirstParam(ClosureExpr *closure); static SourceLoc getLocEncompassingPotentialLookups(const SourceManager &, SourceLoc endLoc); +static SourceLoc getLocAfterExtendedNominal(const ExtensionDecl *); SourceRange ASTScopeImpl::widenSourceRangeForIgnoredASTNodes( const SourceRange range) const { @@ -264,10 +265,15 @@ SourceRange GenericParamScope::getSourceRangeOfThisASTNode( // is visible from the start of the body. if (auto *protoDecl = dyn_cast(nOrE)) return SourceRange(protoDecl->getBraces().Start, protoDecl->getEndLoc()); - auto startLoc = paramList->getSourceRange().Start; - if (startLoc.isInvalid()) - startLoc = holder->getStartLoc(); - return SourceRange(startLoc, holder->getEndLoc()); + const auto startLoc = paramList->getSourceRange().Start; + const auto validStartLoc = + startLoc.isValid() ? startLoc : holder->getStartLoc(); + // Since ExtensionScope (whole portion) range doesn't start till after the + // extended nominal, the range here must be pushed back, too. + if (auto const *const ext = dyn_cast(holder)) { + return SourceRange(getLocAfterExtendedNominal(ext), ext->getEndLoc()); + } + return SourceRange(validStartLoc, holder->getEndLoc()); } SourceRange ASTSourceFileScope::getSourceRangeOfThisASTNode( @@ -296,11 +302,22 @@ SourceRange GenericTypeOrExtensionWholePortion::getChildlessSourceRangeOf( auto r = d->getSourceRangeIncludingAttrs(); if (r.Start.isValid()) { ASTScopeAssert(r.End.isValid(), "Start valid imples end valid."); - return r; + return scope->moveStartPastExtendedNominal(r); } return d->getSourceRange(); } +SourceRange +ExtensionScope::moveStartPastExtendedNominal(const SourceRange sr) const { + return SourceRange(getLocAfterExtendedNominal(decl), sr.End); +} + +SourceRange +GenericTypeScope::moveStartPastExtendedNominal(const SourceRange sr) const { + // There is no extended nominal + return sr; +} + SourceRange GenericTypeOrExtensionWherePortion::getChildlessSourceRangeOf( const GenericTypeOrExtensionScope *scope, const bool omitAssertions) const { return scope->getGenericContext()->getTrailingWhereClause()->getSourceRange(); @@ -557,8 +574,12 @@ static bool isInterpolatedStringLiteral(const Token& tok) { Segments.front().Kind != Lexer::StringSegment::Literal; } -// If right brace is missing, the source range of the body will end -// at the last token, which may be a one of the special cases below. +/// If right brace is missing, the source range of the body will end +/// at the last token, which may be a one of the special cases below. +/// This work is only needed for *unexpanded* scopes because unioning the range +/// with the children will do the same thing for an expanded scope. +/// It is also needed for ignored \c ASTNodes, which may be, e.g. \c +/// InterpolatedStringLiterals static SourceLoc getLocEncompassingPotentialLookups(const SourceManager &SM, const SourceLoc endLoc) { const auto tok = Lexer::getTokenAtLocation(SM, endLoc); @@ -594,9 +615,15 @@ SourceRange AbstractFunctionBodyScope::sourceRangeForDeferredExpansion() const { SourceRange GenericTypeOrExtensionWholePortion::sourceRangeForDeferredExpansion( const IterableTypeScope *s) const { - const auto range = getChildlessSourceRangeOf(s, false); - return SourceRange(range.Start, getLocEncompassingPotentialLookups( - s->getSourceManager(), range.End)); + const auto rangeOfThisNodeWithoutChildren = + getChildlessSourceRangeOf(s, false); + const auto rangeExtendedForFinalToken = SourceRange( + rangeOfThisNodeWithoutChildren.Start, + getLocEncompassingPotentialLookups(s->getSourceManager(), + rangeOfThisNodeWithoutChildren.End)); + const auto rangePastExtendedNominal = + s->moveStartPastExtendedNominal(rangeExtendedForFinalToken); + return rangePastExtendedNominal; } SourceRange GenericTypeOrExtensionWherePortion::sourceRangeForDeferredExpansion( @@ -714,3 +741,12 @@ AbstractFunctionDeclScope::getParmsSourceLocOfAFD(AbstractFunctionDecl *decl) { : fd->getParameters()->getLParenLoc(); // clang-format on } + +SourceLoc getLocAfterExtendedNominal(const ExtensionDecl *const ext) { + const auto *const etr = ext->getExtendedTypeRepr(); + if (!etr) + return ext->getStartLoc(); + const auto &SM = ext->getASTContext().SourceMgr; + return Lexer::getCharSourceRangeFromSourceRange(SM, etr->getSourceRange()) + .getEnd(); +} From 80e7a1f8fc32d056b27d1edfdb0c03b848f8466e Mon Sep 17 00:00:00 2001 From: David Ungar Date: Thu, 19 Sep 2019 19:18:50 -0700 Subject: [PATCH 144/199] Remove debug code --- lib/AST/ASTScopeLookup.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/AST/ASTScopeLookup.cpp b/lib/AST/ASTScopeLookup.cpp index f62ae897c6bb5..d88fd4a5c9c48 100644 --- a/lib/AST/ASTScopeLookup.cpp +++ b/lib/AST/ASTScopeLookup.cpp @@ -62,14 +62,6 @@ const ASTScopeImpl *ASTScopeImpl::findStartingScopeForLookup( if (name.isOperator()) return fileScope; // operators always at file scope - { - const SourceManager &SM = fileScope->getSourceManager(); - if (SM.getLineAndColumn(loc) == - std::make_pair(271, 38) && - SM.getIdentifierForBuffer(SM.findBufferContainingLoc(loc)) - .endswith("CompilerProtocols.swift")) - llvm::errs() << "HERE\n"; - } const auto innermost = fileScope->findInnermostEnclosingScope(loc, nullptr); // The legacy lookup code gets passed both a SourceLoc and a starting context. From b47bd97a3ba1619fe36d185fdb26bc7e987f3dc1 Mon Sep 17 00:00:00 2001 From: David Ungar Date: Thu, 19 Sep 2019 19:21:54 -0700 Subject: [PATCH 145/199] De-experimentalify --- lib/AST/UnqualifiedLookup.cpp | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/lib/AST/UnqualifiedLookup.cpp b/lib/AST/UnqualifiedLookup.cpp index 2f8841e031437..3486a74754104 100644 --- a/lib/AST/UnqualifiedLookup.cpp +++ b/lib/AST/UnqualifiedLookup.cpp @@ -226,15 +226,15 @@ namespace { whereToLook, isCascadingUse.getValueOr(resolution)}; } }; - - bool useASTScopesForExperimentalLookup() const; - + + bool useASTScopesForLookup() const; + /// For testing, assume this lookup is enabled: - bool useASTScopesForExperimentalLookupIfEnabled() const; - + bool useASTScopesForLookupIfEnabled() const; + void lookUpTopLevelNamesInModuleScopeContext(DeclContext *); - void experimentallyLookInASTScopes(); + void lookInASTScopes(); /// Can lookup stop searching for results, assuming hasn't looked for outer /// results yet? @@ -482,13 +482,13 @@ void UnqualifiedLookupFactory::performUnqualifiedLookup() { ContextAndUnresolvedIsCascadingUse contextAndIsCascadingUse{ DC, initialIsCascadingUse}; const bool compareToASTScopes = Ctx.LangOpts.CompareToASTScopeLookup; - if (useASTScopesForExperimentalLookup() && !compareToASTScopes) { + if (useASTScopesForLookup() && !compareToASTScopes) { static bool haveWarned = false; if (!haveWarned && Ctx.LangOpts.WarnIfASTScopeLookup) { haveWarned = true; llvm::errs() << "WARNING: TRYING Scope exclusively\n"; } - experimentallyLookInASTScopes(); + lookInASTScopes(); return; } @@ -501,12 +501,12 @@ void UnqualifiedLookupFactory::performUnqualifiedLookup() { else lookupNamesIntroducedBy(contextAndIsCascadingUse); - if (compareToASTScopes && useASTScopesForExperimentalLookupIfEnabled()) { + if (compareToASTScopes && useASTScopesForLookupIfEnabled()) { ResultsVector results; size_t indexOfFirstOuterResult = 0; UnqualifiedLookupFactory scopeLookup(Name, DC, Loc, options, results, indexOfFirstOuterResult); - scopeLookup.experimentallyLookInASTScopes(); + scopeLookup.lookInASTScopes(); assert(verifyEqualTo(std::move(scopeLookup), "UnqualifedLookup", "Scope lookup")); } @@ -533,13 +533,11 @@ void UnqualifiedLookupFactory::lookUpTopLevelNamesInModuleScopeContext( recordCompletionOfAScope(); } -bool UnqualifiedLookupFactory::useASTScopesForExperimentalLookup() const { - return Ctx.LangOpts.EnableASTScopeLookup && - useASTScopesForExperimentalLookupIfEnabled(); +bool UnqualifiedLookupFactory::useASTScopesForLookup() const { + return Ctx.LangOpts.EnableASTScopeLookup && useASTScopesForLookupIfEnabled(); } -bool UnqualifiedLookupFactory::useASTScopesForExperimentalLookupIfEnabled() - const { +bool UnqualifiedLookupFactory::useASTScopesForLookupIfEnabled() const { if (!Loc.isValid()) return false; const auto *const SF = DC->getParentSourceFile(); @@ -1101,7 +1099,7 @@ UnqualifiedLookupFactory::ResultFinderForTypeContext::findSelfBounds( #pragma mark ASTScopeImpl support -void UnqualifiedLookupFactory::experimentallyLookInASTScopes() { +void UnqualifiedLookupFactory::lookInASTScopes() { ASTScopeDeclConsumerForUnqualifiedLookup consumer(*this); @@ -1145,7 +1143,7 @@ bool ASTScopeDeclConsumerForUnqualifiedLookup::consume( // In order to preserve the behavior of the existing context-based lookup, // which finds all results for non-local variables at the top level instead // of stopping at the first one, ignore results at the top level that are - // not local variables. The caller \c experimentallyLookInASTScopes will + // not local variables. The caller \c lookInASTScopes will // then do the appropriate work when the scope lookup fails. In // FindLocalVal::visitBraceStmt, it sees PatternBindingDecls, not VarDecls, // so a VarDecl at top level would not be found by the context-based lookup. From 87535dfd84bbddd887c52153272afd6271fac2cf Mon Sep 17 00:00:00 2001 From: David Ungar Date: Thu, 19 Sep 2019 19:23:07 -0700 Subject: [PATCH 146/199] Silence a warning --- lib/AST/UnqualifiedLookup.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/AST/UnqualifiedLookup.cpp b/lib/AST/UnqualifiedLookup.cpp index 3486a74754104..ddd4ec710f71c 100644 --- a/lib/AST/UnqualifiedLookup.cpp +++ b/lib/AST/UnqualifiedLookup.cpp @@ -473,6 +473,7 @@ void UnqualifiedLookupFactory::performUnqualifiedLookup() { #ifndef NDEBUG ++lookupCounter; auto localCounter = lookupCounter; + (void)localCounter; // for debugging #endif FrontendStatsTracer StatsTracer(Ctx.Stats, "performUnqualifedLookup", DC->getParentSourceFile()); From a9a9069591534f6fc5df8a41118ff022355f2a4f Mon Sep 17 00:00:00 2001 From: David Ungar Date: Thu, 19 Sep 2019 23:10:41 -0700 Subject: [PATCH 147/199] change compare-to-astScope-lookup to crosscheck-unqualified-lookup --- include/swift/Basic/LangOptions.h | 2 +- include/swift/Option/FrontendOptions.td | 4 +-- lib/AST/UnqualifiedLookup.cpp | 38 ++++++++++++++----------- lib/Frontend/CompilerInvocation.cpp | 3 +- 4 files changed, 27 insertions(+), 20 deletions(-) diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 9d12b808742ca..dde60dca3602f 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -252,7 +252,7 @@ namespace swift { bool DisableParserLookup = false; /// Should we compare to ASTScope-based resolution for debugging? - bool CompareToASTScopeLookup = false; + bool CrosscheckUnqualifiedLookup = false; /// Should we stress ASTScope-based resolution for debugging? bool StressASTScopeLookup = false; diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 7867a48f70114..a722371acea8c 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -122,8 +122,8 @@ def disable_target_os_checking : Flag<["-"], "disable-target-os-checking">, HelpText<"Disable checking the target OS of serialized modules">; -def compare_to_astscope_lookup : Flag<["-"], "compare-to-astscope-lookup">, - HelpText<"Compare legacy to ASTScope-based unqualified name lookup (for debugging)">; +def crosscheck_unqualified_lookup : Flag<["-"], "crosscheck-unqualified-lookup">, + HelpText<"Compare legacy DeclContext- to ASTScope-based unqualified name lookup (for debugging)">; def stress_astscope_lookup : Flag<["-"], "stress-astscope-lookup">, HelpText<"Stress ASTScope-based unqualified name lookup (for testing)">; diff --git a/lib/AST/UnqualifiedLookup.cpp b/lib/AST/UnqualifiedLookup.cpp index ddd4ec710f71c..72c4f4ea7d694 100644 --- a/lib/AST/UnqualifiedLookup.cpp +++ b/lib/AST/UnqualifiedLookup.cpp @@ -482,34 +482,40 @@ void UnqualifiedLookupFactory::performUnqualifiedLookup() { ContextAndUnresolvedIsCascadingUse contextAndIsCascadingUse{ DC, initialIsCascadingUse}; - const bool compareToASTScopes = Ctx.LangOpts.CompareToASTScopeLookup; - if (useASTScopesForLookup() && !compareToASTScopes) { + const bool crosscheckUnqualifiedLookup = + Ctx.LangOpts.CrosscheckUnqualifiedLookup; + if (useASTScopesForLookup()) { static bool haveWarned = false; if (!haveWarned && Ctx.LangOpts.WarnIfASTScopeLookup) { haveWarned = true; llvm::errs() << "WARNING: TRYING Scope exclusively\n"; } lookInASTScopes(); - return; - } - + } else { #ifndef NDEBUG - stopForDebuggingIfStartingTargetLookup(false); + stopForDebuggingIfStartingTargetLookup(false); #endif - if (Name.isOperator()) - lookupOperatorInDeclContexts(contextAndIsCascadingUse); - else - lookupNamesIntroducedBy(contextAndIsCascadingUse); + if (Name.isOperator()) + lookupOperatorInDeclContexts(contextAndIsCascadingUse); + else + lookupNamesIntroducedBy(contextAndIsCascadingUse); + } - if (compareToASTScopes && useASTScopesForLookupIfEnabled()) { + if (crosscheckUnqualifiedLookup && useASTScopesForLookupIfEnabled()) { ResultsVector results; size_t indexOfFirstOuterResult = 0; - UnqualifiedLookupFactory scopeLookup(Name, DC, Loc, options, - results, indexOfFirstOuterResult); - scopeLookup.lookInASTScopes(); - assert(verifyEqualTo(std::move(scopeLookup), "UnqualifedLookup", - "Scope lookup")); + UnqualifiedLookupFactory altLookup(Name, DC, Loc, options, results, + indexOfFirstOuterResult); + if (!useASTScopesForLookup()) + altLookup.lookInASTScopes(); + else if (Name.isOperator()) + altLookup.lookupOperatorInDeclContexts(contextAndIsCascadingUse); + else + altLookup.lookupNamesIntroducedBy(contextAndIsCascadingUse); + + assert( + verifyEqualTo(std::move(altLookup), "main lookup", "alternate lookup")); } } diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 924be6a00823f..da4188082c5cd 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -337,7 +337,8 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Args.hasFlag(options::OPT_enable_astscope_lookup, options::OPT_disable_astscope_lookup, Opts.EnableASTScopeLookup) || Opts.DisableParserLookup; - Opts.CompareToASTScopeLookup |= Args.hasArg(OPT_compare_to_astscope_lookup); + Opts.CrosscheckUnqualifiedLookup |= + Args.hasArg(OPT_crosscheck_unqualified_lookup); Opts.StressASTScopeLookup |= Args.hasArg(OPT_stress_astscope_lookup); Opts.WarnIfASTScopeLookup |= Args.hasArg(OPT_warn_if_astscope_lookup); Opts.LazyASTScopes |= Args.hasArg(OPT_lazy_astscopes); From c271dc4de63d33ad6b782fc245849cfe2fa68356 Mon Sep 17 00:00:00 2001 From: David Ungar Date: Fri, 20 Sep 2019 12:49:57 -0700 Subject: [PATCH 148/199] Fix typo --- lib/AST/ASTScopeCreation.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index 0749d93d711d8..883b172fdd156 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -1876,7 +1876,6 @@ void AbstractFunctionBodyScope::beCurrent() { } bool AbstractFunctionBodyScope::isCurrent() const { return bodyWhenLastExpanded == decl->getBody(false); - ; } void TopLevelCodeScope::beCurrent() { bodyWhenLastExpanded = decl->getBody(); } From c808eb5a27360722dc8ac601e31ea191be8a7ef4 Mon Sep 17 00:00:00 2001 From: David Ungar Date: Fri, 20 Sep 2019 12:43:45 -0700 Subject: [PATCH 149/199] Don't try to expand ASTSourceFileScope when eagerly building. --- include/swift/AST/ASTScope.h | 1 + lib/AST/ASTScope.cpp | 3 +++ lib/AST/ASTScopeCreation.cpp | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index f76f409844538..60dba13f62d7a 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -206,6 +206,7 @@ class ASTScopeImpl { public: void preOrderDo(function_ref); + void preOrderChildrenDo(function_ref); void postOrderDo(function_ref); #pragma mark - source ranges diff --git a/lib/AST/ASTScope.cpp b/lib/AST/ASTScope.cpp index 220f3526203e3..17dd58355db45 100644 --- a/lib/AST/ASTScope.cpp +++ b/lib/AST/ASTScope.cpp @@ -267,6 +267,9 @@ ExtensionScope::getCorrespondingNominalTypeDecl() const { void ASTScopeImpl::preOrderDo(function_ref fn) { fn(this); + preOrderChildrenDo(fn); +} +void ASTScopeImpl::preOrderChildrenDo(function_ref fn) { for (auto *child : getChildren()) child->preOrderDo(fn); } diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index 883b172fdd156..af39a5cfae0f2 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -758,7 +758,8 @@ ASTSourceFileScope *ASTScope::createScopeTree(SourceFile *SF) { void ASTSourceFileScope::buildScopeTreeEagerly() { scopeCreator->beFreezing(); // Eagerly expand any decls already in the tree. - preOrderDo([&](ASTScopeImpl *s) { s->reexpandIfObsolete(*scopeCreator); }); + preOrderChildrenDo( + [&](ASTScopeImpl *s) { s->reexpandIfObsolete(*scopeCreator); }); addNewDeclsToScopeTree(); scopeCreator->beFrozen(); } From 683310eb74f9d036fcd8c42776c403117aff071c Mon Sep 17 00:00:00 2001 From: David Ungar Date: Fri, 20 Sep 2019 12:49:25 -0700 Subject: [PATCH 150/199] Ever expansion detection. WIP --- include/swift/AST/ASTScope.h | 34 ++++++++++++++---------- lib/AST/ASTScopeCreation.cpp | 50 ++++++++++++++++++++++++++---------- lib/AST/ASTScopeLookup.cpp | 2 ++ 3 files changed, 58 insertions(+), 28 deletions(-) diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index 60dba13f62d7a..840883e50e685 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -138,7 +138,10 @@ class ASTScopeImpl { /// Because expansion returns an insertion point, /// if a scope is reexpanded, the children added NOT by expansion must be /// rescued and reused. - unsigned childrenCountWhenLastExpanded = 0; + /// It's good to know if it was ever expanded, so initialize to an impossible + /// value. + const unsigned childrenCountBeforeExpansion = ~0; + unsigned childrenCountWhenLastExpanded = childrenCountBeforeExpansion; /// Can clear storedChildren, so must remember this bool haveAddedCleanup = false; @@ -327,10 +330,16 @@ class ASTScopeImpl { /// Return the scope into which to place subsequent decls ASTScopeImpl *expandAndBeCurrent(ScopeCreator &); + unsigned getChildrenCountWhenLastExpanded() const; + bool wasEverExpanded() const; + protected: + void setChildrenCountWhenLastExpanded(); + void recordThatIWasExpandedEvenIfNoChildrenWereAdded(); virtual ASTScopeImpl *expandSpecifically(ScopeCreator &) = 0; virtual void beCurrent(); - virtual bool isCurrent() const; + bool isCurrent() const; + virtual bool isCurrentIfWasExpanded() const; private: /// Compare the pre-expasion range with the post-expansion range and return @@ -371,9 +380,6 @@ class ASTScopeImpl { virtual ScopeCreator &getScopeCreator(); -protected: - void setChildrenCountWhenLastExpanded(); - #pragma mark - - creation queries public: virtual bool isThisAnAbstractStorageDecl() const { return false; } @@ -591,7 +597,7 @@ class Portion { getReferrentOfScope(const GenericTypeOrExtensionScope *s) const; virtual void beCurrent(IterableTypeScope *) const = 0; - virtual bool isCurrent(const IterableTypeScope *) const = 0; + virtual bool isCurrentIfWasExpanded(const IterableTypeScope *) const = 0; virtual NullablePtr insertionPointForDeferredExpansion(IterableTypeScope *) const = 0; virtual SourceRange @@ -628,7 +634,7 @@ class Portion { /// lazy, might as well do it for all \c IterableTypeScopes. void beCurrent(IterableTypeScope *) const override; - bool isCurrent(const IterableTypeScope *) const override; + bool isCurrentIfWasExpanded(const IterableTypeScope *) const override; NullablePtr insertionPointForDeferredExpansion(IterableTypeScope *) const override; @@ -674,7 +680,7 @@ class GenericTypeOrExtensionWherePortion final bool omitAssertions) const override; void beCurrent(IterableTypeScope *) const override; - bool isCurrent(const IterableTypeScope *) const override; + bool isCurrentIfWasExpanded(const IterableTypeScope *) const override; NullablePtr insertionPointForDeferredExpansion(IterableTypeScope *) const override; @@ -696,7 +702,7 @@ class IterableTypeBodyPortion final bool omitAssertions) const override; void beCurrent(IterableTypeScope *) const override; - bool isCurrent(const IterableTypeScope *) const override; + bool isCurrentIfWasExpanded(const IterableTypeScope *) const override; NullablePtr insertionPointForDeferredExpansion(IterableTypeScope *) const override; SourceRange @@ -807,7 +813,7 @@ class IterableTypeScope : public GenericTypeScope { protected: void beCurrent() override; - bool isCurrent() const override; + bool isCurrentIfWasExpanded() const override; public: void makeWholeCurrent(); @@ -1041,7 +1047,7 @@ class AbstractFunctionBodyScope : public ASTScopeImpl { protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; void beCurrent() override; - bool isCurrent() const override; + bool isCurrentIfWasExpanded() const override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); @@ -1217,7 +1223,7 @@ class PatternEntryDeclScope final : public AbstractPatternEntryScope { protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; void beCurrent() override; - bool isCurrent() const override; + bool isCurrentIfWasExpanded() const override; private: AnnotatedInsertionPoint @@ -1391,7 +1397,7 @@ class WholeClosureScope final : public AbstractClosureScope { protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; void beCurrent() override; - bool isCurrent() const override; + bool isCurrentIfWasExpanded() const override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); @@ -1462,7 +1468,7 @@ class TopLevelCodeScope final : public ASTScopeImpl { protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; void beCurrent() override; - bool isCurrent() const override; + bool isCurrentIfWasExpanded() const override; private: AnnotatedInsertionPoint diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index af39a5cfae0f2..1fc38b5c8d183 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -774,6 +774,7 @@ void ASTSourceFileScope::addNewDeclsToScopeTree() { insertionPoint = scopeCreator->addSiblingsToScopeTree(insertionPoint, newNodes); numberOfDeclsAlreadySeen = SF->Decls.size(); + recordThatIWasExpandedEvenIfNoChildrenWereAdded(); // Too slow to perform all the time: // ASTScopeAssert(scopeCreator->containsAllDeclContextsFromAST(), @@ -1098,6 +1099,7 @@ ASTScopeImpl *ASTScopeImpl::expandAndBeCurrent(ScopeCreator &scopeCreator) { "accurate before expansion, the insertion point before " "expansion must be the same as after expansion."); } + recordThatIWasExpandedEvenIfNoChildrenWereAdded(); beCurrent(); ASTScopeAssert(checkSourceRangeAfterExpansion(scopeCreator.getASTContext()), "Bad range."); @@ -1743,8 +1745,10 @@ void IterableTypeScope::expandBody(ScopeCreator &scopeCreator) { bool ASTScopeImpl::reexpandIfObsolete(ScopeCreator &scopeCreator) { if (scopeCreator.getIsFrozen() || (isCurrent() && - !scopeCreator.getASTContext().LangOpts.StressASTScopeLookup)) + !scopeCreator.getASTContext().LangOpts.StressASTScopeLookup)) { + ASTScopeAssert(wasEverExpanded(), "Cannot be current if unexpanded."); return false; + } reexpand(scopeCreator); return true; } @@ -1830,40 +1834,45 @@ IterableTypeBodyPortion::insertionPointForDeferredExpansion( return s->getParent().get(); } +bool ASTScopeImpl::isCurrent() const { + return wasEverExpanded() && isCurrentIfWasExpanded(); +} void ASTScopeImpl::beCurrent() {} -bool ASTScopeImpl::isCurrent() const { return true; } +bool ASTScopeImpl::isCurrentIfWasExpanded() const { return true; } void IterableTypeScope::beCurrent() { portion->beCurrent(this); } -bool IterableTypeScope::isCurrent() const { return portion->isCurrent(this); } +bool IterableTypeScope::isCurrentIfWasExpanded() const { + return portion->isCurrentIfWasExpanded(this); +} void GenericTypeOrExtensionWholePortion::beCurrent(IterableTypeScope *s) const { s->makeWholeCurrent(); } -bool GenericTypeOrExtensionWholePortion::isCurrent( +bool GenericTypeOrExtensionWholePortion::isCurrentIfWasExpanded( const IterableTypeScope *s) const { return s->isWholeCurrent(); } void GenericTypeOrExtensionWherePortion::beCurrent(IterableTypeScope *) const {} -bool GenericTypeOrExtensionWherePortion::isCurrent( +bool GenericTypeOrExtensionWherePortion::isCurrentIfWasExpanded( const IterableTypeScope *) const { return true; } void IterableTypeBodyPortion::beCurrent(IterableTypeScope *s) const { s->makeBodyCurrent(); } -bool IterableTypeBodyPortion::isCurrent(const IterableTypeScope *s) const { +bool IterableTypeBodyPortion::isCurrentIfWasExpanded( + const IterableTypeScope *s) const { return s->isBodyCurrent(); } void IterableTypeScope::makeWholeCurrent() { - ASTScopeAssert(!shouldHaveABody() || !getChildren().empty(), - "Should have been expanded"); + ASTScopeAssert(wasEverExpanded(), "Should have been expanded"); } bool IterableTypeScope::isWholeCurrent() const { // Whole starts out unexpanded, and is lazily built but will have at least a // body scope child - return !getChildren().empty(); + return wasEverExpanded(); } void IterableTypeScope::makeBodyCurrent() { memberCount = getIterableDeclContext().get()->getMemberCount(); @@ -1875,12 +1884,12 @@ bool IterableTypeScope::isBodyCurrent() const { void AbstractFunctionBodyScope::beCurrent() { bodyWhenLastExpanded = decl->getBody(false); } -bool AbstractFunctionBodyScope::isCurrent() const { +bool AbstractFunctionBodyScope::isCurrentIfWasExpanded() const { return bodyWhenLastExpanded == decl->getBody(false); } void TopLevelCodeScope::beCurrent() { bodyWhenLastExpanded = decl->getBody(); } -bool TopLevelCodeScope::isCurrent() const { +bool TopLevelCodeScope::isCurrentIfWasExpanded() const { return bodyWhenLastExpanded == decl->getBody(); } @@ -1899,7 +1908,7 @@ void PatternEntryDeclScope::beCurrent() { return; varCountWhenLastExpanded = countVars(getPatternEntry()); } -bool PatternEntryDeclScope::isCurrent() const { +bool PatternEntryDeclScope::isCurrentIfWasExpanded() const { if (initWhenLastExpanded != getPatternEntry().getOriginalInit()) return false; if (assumeVarsDoNotGetAdded && varCountWhenLastExpanded) { @@ -1913,7 +1922,7 @@ bool PatternEntryDeclScope::isCurrent() const { void WholeClosureScope::beCurrent() { bodyWhenLastExpanded = closureExpr->getBody(); } -bool WholeClosureScope::isCurrent() const { +bool WholeClosureScope::isCurrentIfWasExpanded() const { return bodyWhenLastExpanded == closureExpr->getBody(); } @@ -1933,9 +1942,12 @@ NullablePtr TopLevelCodeScope::getParentOfRescuedScopes() { #pragma mark rescuing & reusing std::vector ASTScopeImpl::rescueScopesToReuse() { + // If I was never expanded, then there won't be any rescuable scopes. + if (!wasEverExpanded()) + return {}; if (auto *p = getParentOfRescuedScopes().getPtrOrNull()) { return p->rescueYoungestChildren(p->getChildren().size() - - p->childrenCountWhenLastExpanded); + p->getChildrenCountWhenLastExpanded()); } return {}; } @@ -1967,9 +1979,19 @@ ASTScopeImpl::rescueYoungestChildren(const unsigned int count) { return youngestChildren; } +unsigned ASTScopeImpl::getChildrenCountWhenLastExpanded() const { + ASTScopeAssert(wasEverExpanded(), "meaningless"); + return childrenCountWhenLastExpanded; +} +bool ASTScopeImpl::wasEverExpanded() const { + return childrenCountWhenLastExpanded != childrenCountBeforeExpansion; +} void ASTScopeImpl::setChildrenCountWhenLastExpanded() { childrenCountWhenLastExpanded = getChildren().size(); } +void ASTScopeImpl::recordThatIWasExpandedEvenIfNoChildrenWereAdded() { + setChildrenCountWhenLastExpanded(); +} bool AbstractFunctionDeclScope::shouldCreateAccessorScope( const AccessorDecl *const ad) { diff --git a/lib/AST/ASTScopeLookup.cpp b/lib/AST/ASTScopeLookup.cpp index d88fd4a5c9c48..84e13d90ddeda 100644 --- a/lib/AST/ASTScopeLookup.cpp +++ b/lib/AST/ASTScopeLookup.cpp @@ -63,6 +63,8 @@ const ASTScopeImpl *ASTScopeImpl::findStartingScopeForLookup( return fileScope; // operators always at file scope const auto innermost = fileScope->findInnermostEnclosingScope(loc, nullptr); + ASTScopeAssert(innermost->wasEverExpanded(), + "If looking in a scope, it must have been expanded."); // The legacy lookup code gets passed both a SourceLoc and a starting context. // However, our ultimate intent is for clients to not have to pass in a From c17d9ae7bc313a11250d9c841e01a7614e1f4912 Mon Sep 17 00:00:00 2001 From: David Ungar Date: Fri, 20 Sep 2019 13:24:18 -0700 Subject: [PATCH 151/199] Radar tagging --- include/swift/AST/ASTScope.h | 1 + lib/AST/ASTScopeCreation.cpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index 840883e50e685..0bd9f26bb3f22 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -527,6 +527,7 @@ class ASTSourceFileScope final : public ASTScopeImpl { /// The number of \c Decls in the \c SourceFile that were already seen. /// Since parsing can be interleaved with type-checking, on every /// lookup, look at creating scopes for any \c Decls beyond this number. + /// rdar://55562483 Unify with numberOfChildrenWhenLastExpanded int numberOfDeclsAlreadySeen = 0; ASTSourceFileScope(SourceFile *SF, ScopeCreator *scopeCreator); diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index 1fc38b5c8d183..710af9e24109a 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -773,6 +773,9 @@ void ASTSourceFileScope::addNewDeclsToScopeTree() { std::vector newNodes(newDecls.begin(), newDecls.end()); insertionPoint = scopeCreator->addSiblingsToScopeTree(insertionPoint, newNodes); + + // TODO: use childrenCountWhenLastExpanded & regular expansion machinery for ASTSourceFileScope + // rdar://55562483 numberOfDeclsAlreadySeen = SF->Decls.size(); recordThatIWasExpandedEvenIfNoChildrenWereAdded(); From ae7469b5331d83ad7dc1b43bce83ef7f6b15518e Mon Sep 17 00:00:00 2001 From: David Ungar Date: Fri, 20 Sep 2019 21:56:51 -0700 Subject: [PATCH 152/199] Hacked not-so-lazy --- lib/AST/ASTScopeCreation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index 710af9e24109a..e308f18a714bf 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -651,7 +651,7 @@ class ScopeCreator final { } bool shouldBeLazy() const { - return !getIsFreezing() && ctx.LangOpts.LazyASTScopes; + return /*!getIsFreezing() &&*/ ctx.LangOpts.LazyASTScopes; } public: @@ -1746,7 +1746,7 @@ void IterableTypeScope::expandBody(ScopeCreator &scopeCreator) { #pragma mark - reexpandIfObsolete bool ASTScopeImpl::reexpandIfObsolete(ScopeCreator &scopeCreator) { - if (scopeCreator.getIsFrozen() || + if (/* scopeCreator.getIsFrozen() || */ (isCurrent() && !scopeCreator.getASTContext().LangOpts.StressASTScopeLookup)) { ASTScopeAssert(wasEverExpanded(), "Cannot be current if unexpanded."); From 6e790eacc3db50689e82a039b67d5446bcd083fe Mon Sep 17 00:00:00 2001 From: David Ungar Date: Fri, 20 Sep 2019 22:03:06 -0700 Subject: [PATCH 153/199] Rm temperature --- lib/AST/ASTScopeCreation.cpp | 37 ++++++------------------------------ 1 file changed, 6 insertions(+), 31 deletions(-) diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index e308f18a714bf..270d0b3ed199b 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -185,27 +185,9 @@ class ScopeCreator final { /// For allocating scopes. ASTContext &ctx; -public: - /// Because type checking can mutate the AST, eagerly build the tree, then - /// freeze it - enum class Temperature { - Warm, // Can be lazy - Freezing, // Should expand everything eagerly - Frozen // No more changes, except when Decls are added to the source file - }; - -private: - /// Because type checking can mutate the AST, eagerly build the tree, then - /// freeze it - Temperature temperature = Temperature::Warm; - public: ASTSourceFileScope *const sourceFileScope; ASTContext &getASTContext() const { return ctx; } - bool getIsFrozen() const { return temperature == Temperature::Frozen; } - bool getIsFreezing() const { return temperature == Temperature::Freezing; } - void beFreezing() { temperature = Temperature::Freezing; } - void beFrozen() { temperature = Temperature::Frozen; } /// The AST can have duplicate nodes, and we don't want to create scopes for /// those. @@ -650,9 +632,7 @@ class ScopeCreator final { return !n.isDecl(DeclKind::Var); } - bool shouldBeLazy() const { - return /*!getIsFreezing() &&*/ ctx.LangOpts.LazyASTScopes; - } + bool shouldBeLazy() const { return ctx.LangOpts.LazyASTScopes; } public: /// For debugging. Return true if scope tree contains all the decl contexts in @@ -662,11 +642,9 @@ class ScopeCreator final { auto allDeclContexts = findLocalizableDeclContextsInAST(); llvm::DenseMap bogusDCs; bool rebuilt = false; - if (!getIsFrozen()) { - sourceFileScope->preOrderDo([&](ASTScopeImpl *scope) { - rebuilt |= scope->reexpandIfObsolete(*this); - }); - } + sourceFileScope->preOrderDo([&](ASTScopeImpl *scope) { + rebuilt |= scope->reexpandIfObsolete(*this); + }); sourceFileScope->postOrderDo([&](ASTScopeImpl *scope) { if (auto *dc = scope->getDeclContext().getPtrOrNull()) { auto iter = allDeclContexts.find(dc); @@ -756,12 +734,10 @@ ASTSourceFileScope *ASTScope::createScopeTree(SourceFile *SF) { } void ASTSourceFileScope::buildScopeTreeEagerly() { - scopeCreator->beFreezing(); // Eagerly expand any decls already in the tree. preOrderChildrenDo( [&](ASTScopeImpl *s) { s->reexpandIfObsolete(*scopeCreator); }); addNewDeclsToScopeTree(); - scopeCreator->beFrozen(); } void ASTSourceFileScope::addNewDeclsToScopeTree() { @@ -1746,9 +1722,8 @@ void IterableTypeScope::expandBody(ScopeCreator &scopeCreator) { #pragma mark - reexpandIfObsolete bool ASTScopeImpl::reexpandIfObsolete(ScopeCreator &scopeCreator) { - if (/* scopeCreator.getIsFrozen() || */ - (isCurrent() && - !scopeCreator.getASTContext().LangOpts.StressASTScopeLookup)) { + if (isCurrent() && + !scopeCreator.getASTContext().LangOpts.StressASTScopeLookup) { ASTScopeAssert(wasEverExpanded(), "Cannot be current if unexpanded."); return false; } From c7cd4abe2061f7e05b64b135170d9f6f176ff3d0 Mon Sep 17 00:00:00 2001 From: David Ungar Date: Sat, 21 Sep 2019 09:51:58 -0700 Subject: [PATCH 154/199] Fix scope test --- test/NameBinding/scope_map_top_level.swift | 41 ++++++++++++---------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/test/NameBinding/scope_map_top_level.swift b/test/NameBinding/scope_map_top_level.swift index ffd6e3f77c101..7dc64dee40f80 100644 --- a/test/NameBinding/scope_map_top_level.swift +++ b/test/NameBinding/scope_map_top_level.swift @@ -27,31 +27,36 @@ var i: Int = b.my_identity() // CHECK-EXPANDED: ***Complete scope map*** // CHECK-EXPANDED-NEXT: ASTSourceFileScope {{.*}}, (uncached) [1:1 - 6{{.*}}:1] 'SOURCE_DIR{{[/\\]}}test{{[/\\]}}NameBinding{{[/\\]}}scope_map_top_level.swift' -// CHECK-EXPANDED-NEXT: |-NominalTypeDeclScope {{.*}}, [4:1 - 4:13] -// CHECK-EXPANDED-NEXT: `-NominalTypeBodyScope {{.*}}, [4:11 - 4:13] -// CHECK-EXPANDED-NEXT: `-TopLevelCodeScope {{.*}}, [6:1 - 21:28] -// CHECK-EXPANDED-NEXT: `-BraceStmtScope {{.*}}, [6:1 - 21:28] +// CHECK-EXPANDED-NEXT: |-NominalTypeDeclScope {{.*}}, [4:1 - 4:13] +// CHECK-EXPANDED-NEXT: `-NominalTypeBodyScope {{.*}}, [4:11 - 4:13] +// CHECK-EXPANDED-NEXT: `-TopLevelCodeScope {{.*}}, [6:1 - 21:28] +// CHECK-EXPANDED-NEXT: `-BraceStmtScope {{.*}}, [6:1 - 21:28] // CHECK-EXPANDED-NEXT: |-PatternEntryDeclScope {{.*}}, [6:5 - 6:15] entry 0 'a' // CHECK-EXPANDED-NEXT: `-PatternEntryInitializerScope {{.*}}, [6:15 - 6:15] entry 0 'a' -// CHECK-EXPANDED-NEXT: `-TopLevelCodeScope {{.*}}, [8:1 - 21:28] -// CHECK-EXPANDED-NEXT: `-BraceStmtScope {{.*}}, [8:1 - 21:28] -// CHECK-EXPANDED-NEXT: `-GuardStmtScope {{.*}}, [8:1 - 21:28] +// CHECK-EXPANDED-NEXT: `-TopLevelCodeScope {{.*}}, [8:1 - 21:28] +// CHECK-EXPANDED-NEXT: `-BraceStmtScope {{.*}}, [8:1 - 21:28] +// CHECK-EXPANDED-NEXT: `-GuardStmtScope {{.*}}, [8:1 - 21:28] // CHECK-EXPANDED-NEXT: |-ConditionalClauseScope, [8:7 - 8:22] index 0 // CHECK-EXPANDED-NEXT: `-ConditionalClausePatternUseScope, [8:22 - 8:22] let b? -// CHECK-EXPANDED-NEXT: |-BraceStmtScope {{.*}}, [8:22 - 9:1] -// CHECK-EXPANDED-NEXT: `-LookupParentDiversionScope, [9:1 - 21:28] +// CHECK-EXPANDED-NEXT: |-BraceStmtScope {{.*}}, [8:22 - 9:1] +// CHECK-EXPANDED-NEXT: `-LookupParentDiversionScope, [9:1 - 21:28] // CHECK-EXPANDED-NEXT: |-AbstractFunctionDeclScope {{.*}}, [11:1 - 11:13] 'foo()' -// CHECK-EXPANDED-NEXT: `-ParameterListScope {{.*}}, [11:9 - 11:13] -// CHECK-EXPANDED-NEXT: `-PureFunctionBodyScope {{.*}}, [11:12 - 11:13] -// CHECK-EXPANDED-NEXT: `-TopLevelCodeScope {{.*}}, [13:1 - 21:28] -// CHECK-EXPANDED-NEXT: `-BraceStmtScope {{.*}}, [13:1 - 21:28] +// CHECK-EXPANDED-NEXT: `-ParameterListScope {{.*}}, [11:9 - 11:13] +// CHECK-EXPANDED-NEXT: `-PureFunctionBodyScope {{.*}}, [11:12 - 11:13] +// CHECK-EXPANDED-NEXT: `-BraceStmtScope {{.*}}, [11:12 - 11:13] +// CHECK-EXPANDED-NEXT: `-TopLevelCodeScope {{.*}}, [13:1 - 21:28] +// CHECK-EXPANDED-NEXT: `-BraceStmtScope {{.*}}, [13:1 - 21:28] // CHECK-EXPANDED-NEXT: |-PatternEntryDeclScope {{.*}}, [13:5 - 13:9] entry 0 'c' // CHECK-EXPANDED-NEXT: `-PatternEntryInitializerScope {{.*}}, [13:9 - 13:9] entry 0 'c' -// CHECK-EXPANDED-NEXT: |-TypeAliasDeclScope {{.*}}, [15:1 - 15:15] -// CHECK-EXPANDED-NEXT: |-ExtensionDeclScope {{.*}}, [17:1 - 19:1] -// CHECK-EXPANDED-NEXT: `-ExtensionBodyScope {{.*}}, [17:15 - 19:1] -// CHECK-EXPANDED-NEXT: `-TopLevelCodeScope {{.*}}, [21:1 - 21:28] -// CHECK-EXPANDED-NEXT: `-BraceStmtScope {{.*}}, [21:1 - 21:28] +// CHECK-EXPANDED-NEXT: |-TypeAliasDeclScope {{.*}}, [15:1 - 15:15] +// CHECK-EXPANDED-NEXT: |-ExtensionDeclScope {{.*}}, [17:14 - 19:1] +// CHECK-EXPANDED-NEXT: `-ExtensionBodyScope {{.*}}, [17:15 - 19:1] +// CHECK-EXPANDED-NEXT: `-AbstractFunctionDeclScope {{.*}}, [18:3 - 18:43] 'my_identity()' +// CHECK-EXPANDED-NEXT: `-ParameterListScope {{.*}}, [18:19 - 18:43] +// CHECK-EXPANDED-NEXT: `-MethodBodyScope {{.*}}, [18:29 - 18:43] +// CHECK-EXPANDED-NEXT: `-BraceStmtScope {{.*}}, [18:29 - 18:43] +// CHECK-EXPANDED-NEXT: `-TopLevelCodeScope {{.*}}, [21:1 - 21:28] +// CHECK-EXPANDED-NEXT: `-BraceStmtScope {{.*}}, [21:1 - 21:28] // CHECK-EXPANDED-NEXT: `-PatternEntryDeclScope {{.*}}, [21:5 - 21:28] entry 0 'i' // CHECK-EXPANDED-NEXT: `-PatternEntryInitializerScope {{.*}}, [21:14 - 21:28] entry 0 'i' From 3c891f95320e780defbac0c86bba3ad595b3ce0b Mon Sep 17 00:00:00 2001 From: David Ungar Date: Sat, 21 Sep 2019 09:53:13 -0700 Subject: [PATCH 155/199] Fully eager for printing, just eager enough for type-checking. --- include/swift/AST/ASTScope.h | 4 +++- include/swift/AST/NameLookup.h | 8 +++++--- lib/AST/ASTScopeCreation.cpp | 15 +++++++++++---- lib/FrontendTool/FrontendTool.cpp | 5 ++++- lib/Sema/TypeChecker.cpp | 10 ++++++---- 5 files changed, 29 insertions(+), 13 deletions(-) diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index 0bd9f26bb3f22..399c0064f47e3 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -543,7 +543,9 @@ class ASTSourceFileScope final : public ASTScopeImpl { NullablePtr getDeclContext() const override; void addNewDeclsToScopeTree(); - void buildScopeTreeEagerly(); + void buildFullyExpandedTree(); + void + buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals(); const SourceFile *getSourceFile() const override; NullablePtr addressForPrinting() const override { return SF; } diff --git a/include/swift/AST/NameLookup.h b/include/swift/AST/NameLookup.h index 770f045f0f83c..367018f5ac2e8 100644 --- a/include/swift/AST/NameLookup.h +++ b/include/swift/AST/NameLookup.h @@ -592,9 +592,11 @@ class ASTScope { public: ASTScope(SourceFile *); - /// Cannot be lazy during type-checking because it mutates the AST. - /// So build eagerly before type-checking - void buildScopeTreeEagerly(); + void + buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals(); + + /// Flesh out the tree for dumping + void buildFullyExpandedTree(); /// \return the scopes traversed static llvm::SmallVector diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index 270d0b3ed199b..34ba68c4a4c36 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -724,8 +724,11 @@ class ScopeCreator final { ASTScope::ASTScope(SourceFile *SF) : impl(createScopeTree(SF)) {} -void ASTScope::buildScopeTreeEagerly() { - impl->buildScopeTreeEagerly(); +void ASTScope::buildFullyExpandedTree() { impl->buildFullyExpandedTree(); } + +void ASTScope:: + buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals() { + impl->buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals(); } ASTSourceFileScope *ASTScope::createScopeTree(SourceFile *SF) { @@ -733,10 +736,14 @@ ASTSourceFileScope *ASTScope::createScopeTree(SourceFile *SF) { return scopeCreator->sourceFileScope; } -void ASTSourceFileScope::buildScopeTreeEagerly() { - // Eagerly expand any decls already in the tree. +void ASTSourceFileScope::buildFullyExpandedTree() { + addNewDeclsToScopeTree(); preOrderChildrenDo( [&](ASTScopeImpl *s) { s->reexpandIfObsolete(*scopeCreator); }); +} + +void ASTSourceFileScope:: + buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals() { addNewDeclsToScopeTree(); } diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index fc23df524dd20..e3f45ba415211 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -749,13 +749,16 @@ static void dumpAndPrintScopeMap(CompilerInvocation &Invocation, if (Invocation.getFrontendOptions().DumpScopeMapLocations.empty()) { llvm::errs() << "***Complete scope map***\n"; + scope.buildFullyExpandedTree(); scope.print(llvm::errs()); return; } // Probe each of the locations, and dump what we find. for (auto lineColumn : - Invocation.getFrontendOptions().DumpScopeMapLocations) + Invocation.getFrontendOptions().DumpScopeMapLocations) { + scope.buildFullyExpandedTree(); scope.dumpOneScopeMapLocation(lineColumn); + } } static SourceFile *getPrimaryOrMainSourceFile(CompilerInvocation &Invocation, diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp index ff034d3ff522f..fe07724f29923 100644 --- a/lib/Sema/TypeChecker.cpp +++ b/lib/Sema/TypeChecker.cpp @@ -351,12 +351,14 @@ void swift::performTypeChecking(SourceFile &SF, TopLevelContext &TLC, if (SF.ASTStage == SourceFile::TypeChecked) return; - // Eagerly build a scope tree before type checking - // because type-checking mutates the AST and that throws off the scope-based - // lookups. + // Eagerly build the top-level scopes tree before type checking + // because type-checking expressions mutates the AST and that throws off the + // scope-based lookups. Only the top-level scopes because extensions have not + // been bound yet. if (SF.getASTContext().LangOpts.EnableASTScopeLookup && SF.isSuitableForASTScopes()) - SF.getScope().buildScopeTreeEagerly(); + SF.getScope() + .buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals(); auto &Ctx = SF.getASTContext(); BufferIndirectlyCausingDiagnosticRAII cpr(SF); From 5d87a66edae4b54dbe1853e56614e636f33e0129 Mon Sep 17 00:00:00 2001 From: David Ungar Date: Sat, 21 Sep 2019 16:16:48 -0700 Subject: [PATCH 156/199] Ensure that after pushing start of ExtensionScope after extended type, the end is not before the beginning. --- lib/AST/ASTScopeSourceRange.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/AST/ASTScopeSourceRange.cpp b/lib/AST/ASTScopeSourceRange.cpp index afa0cf23bf45a..71489e086a320 100644 --- a/lib/AST/ASTScopeSourceRange.cpp +++ b/lib/AST/ASTScopeSourceRange.cpp @@ -309,7 +309,12 @@ SourceRange GenericTypeOrExtensionWholePortion::getChildlessSourceRangeOf( SourceRange ExtensionScope::moveStartPastExtendedNominal(const SourceRange sr) const { - return SourceRange(getLocAfterExtendedNominal(decl), sr.End); + const auto start = getLocAfterExtendedNominal(decl); + // Illegal code can have an endLoc that is before the end of the + // ExtendedNominal, so push the end back, too, in that case. + const auto end = + getSourceManager().isBeforeInBuffer(sr.End, start) ? start : sr.End; + return SourceRange(start, end); } SourceRange From 5ca14099a10c53796821883b8cbafb4960008d63 Mon Sep 17 00:00:00 2001 From: David Ungar Date: Sun, 22 Sep 2019 08:57:45 -0700 Subject: [PATCH 157/199] Add comment --- include/swift/AST/ASTScope.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index 399c0064f47e3..113306c64b3e3 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -209,6 +209,7 @@ class ASTScopeImpl { public: void preOrderDo(function_ref); + /// Like preorderDo but without myself. void preOrderChildrenDo(function_ref); void postOrderDo(function_ref); From 9674643779b9f06b283baf739514e22480c0ed0a Mon Sep 17 00:00:00 2001 From: David Ungar Date: Sun, 22 Sep 2019 09:00:35 -0700 Subject: [PATCH 158/199] Comment out potential debugging code issue. --- lib/AST/ASTScopeLookup.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/AST/ASTScopeLookup.cpp b/lib/AST/ASTScopeLookup.cpp index 84e13d90ddeda..486fe4935d3ef 100644 --- a/lib/AST/ASTScopeLookup.cpp +++ b/lib/AST/ASTScopeLookup.cpp @@ -96,8 +96,9 @@ const ASTScopeImpl *ASTScopeImpl::findStartingScopeForLookup( // fileScope->dump(); llvm::errs() << "\n\n"; - if (fileScope->crossCheckWithAST()) - llvm::errs() << "Tree creation missed some DeclContexts.\n"; + // Might distort things + // if (fileScope->crossCheckWithAST()) + // llvm::errs() << "Tree creation missed some DeclContexts.\n"; } ASTScopeAssert(startingScope, "ASTScopeImpl: could not find startingScope"); From 10583f89c6c014537baefb1f772df096a71a0c5c Mon Sep 17 00:00:00 2001 From: David Ungar Date: Sun, 22 Sep 2019 09:01:52 -0700 Subject: [PATCH 159/199] Ensure that reexpansion does not lose scopes. --- include/swift/AST/ASTScope.h | 6 ++++++ lib/AST/ASTScope.cpp | 18 ++++++++++++++++++ lib/AST/ASTScopeCreation.cpp | 2 +- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index 113306c64b3e3..b3d1858580cdb 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -234,6 +234,12 @@ class ASTScopeImpl { bool doesRangeMatch(unsigned start, unsigned end, StringRef file = "", StringRef className = ""); + unsigned countDescendants() const; + + /// Make sure that when the argument is executed, there are as many + /// descendants after as before. + void assertThatTreeDoesNotShrink(function_ref); + private: SourceRange computeSourceRangeOfScope(bool omitAssertions = false) const; SourceRange diff --git a/lib/AST/ASTScope.cpp b/lib/AST/ASTScope.cpp index 17dd58355db45..66d31521fba9b 100644 --- a/lib/AST/ASTScope.cpp +++ b/lib/AST/ASTScope.cpp @@ -288,3 +288,21 @@ const StmtConditionElement & ConditionalClauseScope::getStmtConditionElement() const { return getCond()[index]; } + +unsigned ASTScopeImpl::countDescendants() const { + unsigned count = 0; + const_cast(this)->preOrderDo( + [&](ASTScopeImpl *) { ++count; }); + return count - 1; +} + +void ASTScopeImpl::assertThatTreeDoesNotShrink(function_ref fn) { +#ifndef NDEBUG + unsigned beforeCount = countDescendants(); +#endif + fn(); +#ifndef NDEBUG + unsigned afterCount = countDescendants(); + ASTScopeAssert(beforeCount <= afterCount, "shrank?!"); +#endif +} diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index 34ba68c4a4c36..9de1ae25e344f 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -1734,7 +1734,7 @@ bool ASTScopeImpl::reexpandIfObsolete(ScopeCreator &scopeCreator) { ASTScopeAssert(wasEverExpanded(), "Cannot be current if unexpanded."); return false; } - reexpand(scopeCreator); + assertThatTreeDoesNotShrink([&] { this->reexpand(scopeCreator); }); return true; } From 7f834cdb54a7f9b1bb04eba3f9a6688a6b058d20 Mon Sep 17 00:00:00 2001 From: David Ungar Date: Sun, 22 Sep 2019 09:57:04 -0700 Subject: [PATCH 160/199] renaming to ASTAncestor --- include/swift/AST/ASTScope.h | 14 ++++++----- lib/AST/ASTScopeCreation.cpp | 46 ++++++++++++++++++++++-------------- 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index b3d1858580cdb..a38e93ce4899c 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -193,12 +193,14 @@ class ASTScopeImpl { public: // for addReusedBodyScopes void addChild(ASTScopeImpl *child, ASTContext &); - std::vector rescueYoungestChildren(unsigned count); + std::vector + rescueASTAncestorScopesForReuseFromMe(unsigned count); /// When reexpanding, do we always create a new body? - virtual NullablePtr getParentOfRescuedScopes(); - std::vector rescueScopesToReuse(); - void addReusedScopes(ArrayRef); + virtual NullablePtr getParentOfASTAncestorScopesToBeRescued(); + std::vector + rescueASTAncestorScopesForReuseFromMeOrDescendants(); + void replaceASTAncestorScopes(ArrayRef); private: void removeChildren(); @@ -1073,7 +1075,7 @@ class AbstractFunctionBodyScope : public ASTScopeImpl { Decl *getDecl() const { return decl; } static bool isAMethod(const AbstractFunctionDecl *); - NullablePtr getParentOfRescuedScopes() override; + NullablePtr getParentOfASTAncestorScopesToBeRescued() override; protected: bool lookupLocalsOrMembers(ArrayRef, @@ -1496,7 +1498,7 @@ class TopLevelCodeScope final : public ASTScopeImpl { Decl *getDecl() const { return decl; } NullablePtr getReferrent() const override; - NullablePtr getParentOfRescuedScopes() override; + NullablePtr getParentOfASTAncestorScopesToBeRescued() override; }; /// The \c _@specialize attribute. diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index 9de1ae25e344f..c7314378745fc 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -1739,10 +1739,10 @@ bool ASTScopeImpl::reexpandIfObsolete(ScopeCreator &scopeCreator) { } void ASTScopeImpl::reexpand(ScopeCreator &scopeCreator) { - auto scopesToReuse = rescueScopesToReuse(); + auto astAncestorScopes = rescueASTAncestorScopesForReuseFromMeOrDescendants(); disownDescendants(scopeCreator); expandAndBeCurrent(scopeCreator); - addReusedScopes(scopesToReuse); + replaceASTAncestorScopes(astAncestorScopes); } #pragma mark getScopeCreator @@ -1911,34 +1911,43 @@ bool WholeClosureScope::isCurrentIfWasExpanded() const { return bodyWhenLastExpanded == closureExpr->getBody(); } -#pragma mark getParentOfRescuedScopes -NullablePtr ASTScopeImpl::getParentOfRescuedScopes() { +#pragma mark getParentOfASTAncestorScopesToBeRescued +NullablePtr +ASTScopeImpl::getParentOfASTAncestorScopesToBeRescued() { return this; } NullablePtr -AbstractFunctionBodyScope::getParentOfRescuedScopes() { +AbstractFunctionBodyScope::getParentOfASTAncestorScopesToBeRescued() { // Reexpansion always creates a new body as the first child + // That body contains the scopes to be rescued. return getChildren().empty() ? nullptr : getChildren().front(); } -NullablePtr TopLevelCodeScope::getParentOfRescuedScopes() { +NullablePtr +TopLevelCodeScope::getParentOfASTAncestorScopesToBeRescued() { // Reexpansion always creates a new body as the first child + // That body contains the scopes to be rescued. return getChildren().empty() ? nullptr : getChildren().front(); } #pragma mark rescuing & reusing -std::vector ASTScopeImpl::rescueScopesToReuse() { - // If I was never expanded, then there won't be any rescuable scopes. - if (!wasEverExpanded()) +std::vector +ASTScopeImpl::rescueASTAncestorScopesForReuseFromMeOrDescendants() { +// If I was never expanded, then there won't be any rescuable scopes. + if (!getWasExpanded()) return {}; - if (auto *p = getParentOfRescuedScopes().getPtrOrNull()) { - return p->rescueYoungestChildren(p->getChildren().size() - - p->getChildrenCountWhenLastExpanded()); + if (auto *p = getParentOfASTAncestorScopesToBeRescued().getPtrOrNull()) { + return p->rescueASTAncestorScopesForReuseFromMe( + p->getChildren().size() - p->getChildrenCountWhenLastExpanded()); } + ASTScopeAssert( + scopesFromASTAncestors == 0, + "If receives ASTAncestor scopes, must know where to find parent"); return {}; } -void ASTScopeImpl::addReusedScopes(ArrayRef scopesToAdd) { - auto *p = getParentOfRescuedScopes().getPtrOrNull(); +void ASTScopeImpl::replaceASTAncestorScopes( + ArrayRef scopesToAdd) { + auto *p = getParentOfASTAncestorScopesToBeRescued().getPtrOrNull(); if (!p) { ASTScopeAssert(scopesToAdd.empty(), "Non-empty body disappeared?!"); return; @@ -1952,16 +1961,17 @@ void ASTScopeImpl::addReusedScopes(ArrayRef scopesToAdd) { } std::vector -ASTScopeImpl::rescueYoungestChildren(const unsigned int count) { - std::vector youngestChildren; +ASTScopeImpl::rescueASTAncestorScopesForReuseFromMe(const unsigned int count) { + std::vector astAncestorScopes; for (unsigned i = getChildren().size() - count; i < getChildren().size(); ++i) - youngestChildren.push_back(getChildren()[i]); + astAncestorScopes.push_back(getChildren()[i]); // So they don't get disowned and children cleared. for (unsigned i = 0; i < count; ++i) { storedChildren.back()->emancipate(); storedChildren.pop_back(); + --scopesFromASTAncestors; } - return youngestChildren; + return astAncestorScopes; } unsigned ASTScopeImpl::getChildrenCountWhenLastExpanded() const { From b943a3987fdf073181fa1ef769e014be7cf5b0a8 Mon Sep 17 00:00:00 2001 From: David Ungar Date: Sun, 22 Sep 2019 10:03:12 -0700 Subject: [PATCH 161/199] Use separate bool to record expansion --- include/swift/AST/ASTScope.h | 6 ++++-- lib/AST/ASTScopeCreation.cpp | 21 ++++++++------------- lib/AST/ASTScopeLookup.cpp | 2 +- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index a38e93ce4899c..5056610b7c352 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -135,6 +135,8 @@ class ASTScopeImpl { /// Must clear source range change whenever this changes Children storedChildren; + bool wasExpanded = false; + /// Because expansion returns an insertion point, /// if a scope is reexpanded, the children added NOT by expansion must be /// rescued and reused. @@ -340,11 +342,11 @@ class ASTScopeImpl { ASTScopeImpl *expandAndBeCurrent(ScopeCreator &); unsigned getChildrenCountWhenLastExpanded() const; - bool wasEverExpanded() const; + bool getWasExpanded() const { return wasExpanded; } protected: void setChildrenCountWhenLastExpanded(); - void recordThatIWasExpandedEvenIfNoChildrenWereAdded(); + void setWasExpanded() { wasExpanded = true; } virtual ASTScopeImpl *expandSpecifically(ScopeCreator &) = 0; virtual void beCurrent(); bool isCurrent() const; diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index c7314378745fc..a1924ea8fb0db 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -760,7 +760,7 @@ void ASTSourceFileScope::addNewDeclsToScopeTree() { // TODO: use childrenCountWhenLastExpanded & regular expansion machinery for ASTSourceFileScope // rdar://55562483 numberOfDeclsAlreadySeen = SF->Decls.size(); - recordThatIWasExpandedEvenIfNoChildrenWereAdded(); + setWasExpanded(); // Too slow to perform all the time: // ASTScopeAssert(scopeCreator->containsAllDeclContextsFromAST(), @@ -1085,7 +1085,7 @@ ASTScopeImpl *ASTScopeImpl::expandAndBeCurrent(ScopeCreator &scopeCreator) { "accurate before expansion, the insertion point before " "expansion must be the same as after expansion."); } - recordThatIWasExpandedEvenIfNoChildrenWereAdded(); + setWasExpanded(); beCurrent(); ASTScopeAssert(checkSourceRangeAfterExpansion(scopeCreator.getASTContext()), "Bad range."); @@ -1731,7 +1731,7 @@ void IterableTypeScope::expandBody(ScopeCreator &scopeCreator) { bool ASTScopeImpl::reexpandIfObsolete(ScopeCreator &scopeCreator) { if (isCurrent() && !scopeCreator.getASTContext().LangOpts.StressASTScopeLookup) { - ASTScopeAssert(wasEverExpanded(), "Cannot be current if unexpanded."); + ASTScopeAssert(getWasExpanded(), "Cannot be current if unexpanded."); return false; } assertThatTreeDoesNotShrink([&] { this->reexpand(scopeCreator); }); @@ -1820,7 +1820,7 @@ IterableTypeBodyPortion::insertionPointForDeferredExpansion( } bool ASTScopeImpl::isCurrent() const { - return wasEverExpanded() && isCurrentIfWasExpanded(); + return getWasExpanded() && isCurrentIfWasExpanded(); } void ASTScopeImpl::beCurrent() {} @@ -1852,12 +1852,12 @@ bool IterableTypeBodyPortion::isCurrentIfWasExpanded( } void IterableTypeScope::makeWholeCurrent() { - ASTScopeAssert(wasEverExpanded(), "Should have been expanded"); + ASTScopeAssert(getWasExpanded(), "Should have been expanded"); } bool IterableTypeScope::isWholeCurrent() const { // Whole starts out unexpanded, and is lazily built but will have at least a // body scope child - return wasEverExpanded(); + return getWasExpanded(); } void IterableTypeScope::makeBodyCurrent() { memberCount = getIterableDeclContext().get()->getMemberCount(); @@ -1975,18 +1975,13 @@ ASTScopeImpl::rescueASTAncestorScopesForReuseFromMe(const unsigned int count) { } unsigned ASTScopeImpl::getChildrenCountWhenLastExpanded() const { - ASTScopeAssert(wasEverExpanded(), "meaningless"); + ASTScopeAssert(getWasExpanded(), "meaningless"); return childrenCountWhenLastExpanded; } -bool ASTScopeImpl::wasEverExpanded() const { - return childrenCountWhenLastExpanded != childrenCountBeforeExpansion; -} + void ASTScopeImpl::setChildrenCountWhenLastExpanded() { childrenCountWhenLastExpanded = getChildren().size(); } -void ASTScopeImpl::recordThatIWasExpandedEvenIfNoChildrenWereAdded() { - setChildrenCountWhenLastExpanded(); -} bool AbstractFunctionDeclScope::shouldCreateAccessorScope( const AccessorDecl *const ad) { diff --git a/lib/AST/ASTScopeLookup.cpp b/lib/AST/ASTScopeLookup.cpp index 486fe4935d3ef..a87e754d16f93 100644 --- a/lib/AST/ASTScopeLookup.cpp +++ b/lib/AST/ASTScopeLookup.cpp @@ -63,7 +63,7 @@ const ASTScopeImpl *ASTScopeImpl::findStartingScopeForLookup( return fileScope; // operators always at file scope const auto innermost = fileScope->findInnermostEnclosingScope(loc, nullptr); - ASTScopeAssert(innermost->wasEverExpanded(), + ASTScopeAssert(innermost->getWasExpanded(), "If looking in a scope, it must have been expanded."); // The legacy lookup code gets passed both a SourceLoc and a starting context. From 5144341fe7af386debfc9124ed950b8b9138fce5 Mon Sep 17 00:00:00 2001 From: David Ungar Date: Sun, 22 Sep 2019 11:29:42 -0700 Subject: [PATCH 162/199] Count AST ancestor scopes instead of children when last expanded --- include/swift/AST/ASTScope.h | 17 ++++------- lib/AST/ASTScopeCreation.cpp | 59 ++++++++++++++++++------------------ 2 files changed, 36 insertions(+), 40 deletions(-) diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index 5056610b7c352..b4b5566ff7819 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -137,13 +137,8 @@ class ASTScopeImpl { bool wasExpanded = false; - /// Because expansion returns an insertion point, - /// if a scope is reexpanded, the children added NOT by expansion must be - /// rescued and reused. - /// It's good to know if it was ever expanded, so initialize to an impossible - /// value. - const unsigned childrenCountBeforeExpansion = ~0; - unsigned childrenCountWhenLastExpanded = childrenCountBeforeExpansion; + /// For use-before-def, ASTAncestor scopes may be added to a BraceStmt. + unsigned astAncestorScopeCount = 0; /// Can clear storedChildren, so must remember this bool haveAddedCleanup = false; @@ -195,8 +190,7 @@ class ASTScopeImpl { public: // for addReusedBodyScopes void addChild(ASTScopeImpl *child, ASTContext &); - std::vector - rescueASTAncestorScopesForReuseFromMe(unsigned count); + std::vector rescueASTAncestorScopesForReuseFromMe(); /// When reexpanding, do we always create a new body? virtual NullablePtr getParentOfASTAncestorScopesToBeRescued(); @@ -341,11 +335,12 @@ class ASTScopeImpl { /// Return the scope into which to place subsequent decls ASTScopeImpl *expandAndBeCurrent(ScopeCreator &); - unsigned getChildrenCountWhenLastExpanded() const; + unsigned getASTAncestorScopeCount() const { return astAncestorScopeCount; } bool getWasExpanded() const { return wasExpanded; } protected: - void setChildrenCountWhenLastExpanded(); + void resetASTAncestorScopeCount() { astAncestorScopeCount = 0; } + void increaseASTAncestorScopeCount(unsigned c) { astAncestorScopeCount += c; } void setWasExpanded() { wasExpanded = true; } virtual ASTScopeImpl *expandSpecifically(ScopeCreator &) = 0; virtual void beCurrent(); diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index a1924ea8fb0db..819ab054422be 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -204,15 +204,25 @@ class ScopeCreator final { /// Given an array of ASTNodes or Decl pointers, add them /// Return the resultant insertionPoint - ASTScopeImpl *addSiblingsToScopeTree(ASTScopeImpl *const insertionPoint, - ArrayRef nodesOrDeclsToAdd) { + ASTScopeImpl * + addSiblingsToScopeTree(ASTScopeImpl *const insertionPoint, + ASTScopeImpl *const organicInsertionPoint, + ArrayRef nodesOrDeclsToAdd) { auto *ip = insertionPoint; for (auto nd : expandIfConfigClausesThenCullAndSortElementsOrMembers( nodesOrDeclsToAdd)) { - if (shouldThisNodeBeScopedWhenFoundInSourceFileBraceStmtOrType(nd)) - ip = addToScopeTreeAndReturnInsertionPoint(nd, ip).getPtrOr(ip); - else + if (!shouldThisNodeBeScopedWhenFoundInSourceFileBraceStmtOrType(nd)) { + // FIXME: Could the range get lost if the node is ever reexpanded? ip->widenSourceRangeForIgnoredASTNode(nd); + } else { + const unsigned preCount = ip->getChildren().size(); + auto *const newIP = + addToScopeTreeAndReturnInsertionPoint(nd, ip).getPtrOr(ip); + if (ip != organicInsertionPoint) + ip->increaseASTAncestorScopeCount(ip->getChildren().size() - + preCount); + ip = newIP; + } } return ip; } @@ -755,9 +765,9 @@ void ASTSourceFileScope::addNewDeclsToScopeTree() { ArrayRef newDecls = decls.slice(numberOfDeclsAlreadySeen); std::vector newNodes(newDecls.begin(), newDecls.end()); insertionPoint = - scopeCreator->addSiblingsToScopeTree(insertionPoint, newNodes); + scopeCreator->addSiblingsToScopeTree(insertionPoint, this, newNodes); - // TODO: use childrenCountWhenLastExpanded & regular expansion machinery for ASTSourceFileScope + // TODO: use regular expansion machinery for ASTSourceFileScope // rdar://55562483 numberOfDeclsAlreadySeen = SF->Decls.size(); setWasExpanded(); @@ -1054,9 +1064,6 @@ void ASTScopeImpl::addChild(ASTScopeImpl *child, ASTContext &ctx) { ASTScopeAssert(!child->getParent(), "child should not already have parent"); child->parent = this; clearCachedSourceRangesOfMeAndAncestors(); - // It's possible that some callees do lookups back into the tree. - // So make sure childrenCountWhenLastExpanded is up to date. - setChildrenCountWhenLastExpanded(); } void ASTScopeImpl::removeChildren() { @@ -1262,7 +1269,7 @@ BraceStmtScope::expandAScopeThatCreatesANewInsertionPoint( ScopeCreator &scopeCreator) { // TODO: remove the sort after performing rdar://53254395 auto *insertionPoint = - scopeCreator.addSiblingsToScopeTree(this, stmt->getElements()); + scopeCreator.addSiblingsToScopeTree(this, this, stmt->getElements()); if (auto *s = scopeCreator.getASTContext().Stats) ++s->getFrontendCounters().NumBraceStmtASTScopeExpansions; return { @@ -1721,7 +1728,7 @@ void GenericTypeOrExtensionScope::expandBody(ScopeCreator &) {} void IterableTypeScope::expandBody(ScopeCreator &scopeCreator) { auto nodes = asNodeVector(getIterableDeclContext().get()->getMembers()); - scopeCreator.addSiblingsToScopeTree(this, nodes); + scopeCreator.addSiblingsToScopeTree(this, this, nodes); if (auto *s = scopeCreator.getASTContext().Stats) ++s->getFrontendCounters().NumIterableTypeBodyASTScopeExpansions; } @@ -1741,6 +1748,8 @@ bool ASTScopeImpl::reexpandIfObsolete(ScopeCreator &scopeCreator) { void ASTScopeImpl::reexpand(ScopeCreator &scopeCreator) { auto astAncestorScopes = rescueASTAncestorScopesForReuseFromMeOrDescendants(); disownDescendants(scopeCreator); + // If the expansion recurses back into the tree for lookup, the ASTAncestor + // scopes will have already been rescued and won't be found! HERE expandAndBeCurrent(scopeCreator); replaceASTAncestorScopes(astAncestorScopes); } @@ -1936,11 +1945,10 @@ ASTScopeImpl::rescueASTAncestorScopesForReuseFromMeOrDescendants() { if (!getWasExpanded()) return {}; if (auto *p = getParentOfASTAncestorScopesToBeRescued().getPtrOrNull()) { - return p->rescueASTAncestorScopesForReuseFromMe( - p->getChildren().size() - p->getChildrenCountWhenLastExpanded()); + return p->rescueASTAncestorScopesForReuseFromMe(); } ASTScopeAssert( - scopesFromASTAncestors == 0, + getASTAncestorScopeCount() == 0, "If receives ASTAncestor scopes, must know where to find parent"); return {}; } @@ -1954,35 +1962,28 @@ void ASTScopeImpl::replaceASTAncestorScopes( } auto &ctx = getASTContext(); for (auto *s : scopesToAdd) { - p->addChild(s, ctx); + p->addChild(s, ctx); // NONORGANIC ASTScopeAssert(s->verifyThatThisNodeComeAfterItsPriorSibling(), "Ensure search will work"); } + p->increaseASTAncestorScopeCount(scopesToAdd.size()); } std::vector -ASTScopeImpl::rescueASTAncestorScopesForReuseFromMe(const unsigned int count) { +ASTScopeImpl::rescueASTAncestorScopesForReuseFromMe() { std::vector astAncestorScopes; - for (unsigned i = getChildren().size() - count; i < getChildren().size(); ++i) + for (unsigned i = getChildren().size() - getASTAncestorScopeCount(); + i < getChildren().size(); ++i) astAncestorScopes.push_back(getChildren()[i]); // So they don't get disowned and children cleared. - for (unsigned i = 0; i < count; ++i) { + for (unsigned i = 0; i < getASTAncestorScopeCount(); ++i) { storedChildren.back()->emancipate(); storedChildren.pop_back(); - --scopesFromASTAncestors; } + resetASTAncestorScopeCount(); return astAncestorScopes; } -unsigned ASTScopeImpl::getChildrenCountWhenLastExpanded() const { - ASTScopeAssert(getWasExpanded(), "meaningless"); - return childrenCountWhenLastExpanded; -} - -void ASTScopeImpl::setChildrenCountWhenLastExpanded() { - childrenCountWhenLastExpanded = getChildren().size(); -} - bool AbstractFunctionDeclScope::shouldCreateAccessorScope( const AccessorDecl *const ad) { return isLocalizable(ad); From e59196cb620caf4858e64f6a6a934cb7cdc2c6ca Mon Sep 17 00:00:00 2001 From: David Ungar Date: Sun, 22 Sep 2019 12:04:18 -0700 Subject: [PATCH 163/199] Remove too-restrictive assertion --- lib/AST/ASTScope.cpp | 1 + lib/AST/ASTScopeCreation.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/AST/ASTScope.cpp b/lib/AST/ASTScope.cpp index 66d31521fba9b..63bbd662473d9 100644 --- a/lib/AST/ASTScope.cpp +++ b/lib/AST/ASTScope.cpp @@ -296,6 +296,7 @@ unsigned ASTScopeImpl::countDescendants() const { return count - 1; } +// Can fail if a subscope is lazy and not reexpanded void ASTScopeImpl::assertThatTreeDoesNotShrink(function_ref fn) { #ifndef NDEBUG unsigned beforeCount = countDescendants(); diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index 819ab054422be..976d81ad918a2 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -1741,7 +1741,7 @@ bool ASTScopeImpl::reexpandIfObsolete(ScopeCreator &scopeCreator) { ASTScopeAssert(getWasExpanded(), "Cannot be current if unexpanded."); return false; } - assertThatTreeDoesNotShrink([&] { this->reexpand(scopeCreator); }); + this->reexpand(scopeCreator); return true; } From ef570f9c45f58faf08e0fcf5ccf93702b6647e62 Mon Sep 17 00:00:00 2001 From: David Ungar Date: Sun, 22 Sep 2019 13:36:50 -0700 Subject: [PATCH 164/199] cleanups --- lib/AST/ASTScopeCreation.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index 976d81ad918a2..15849f06e0339 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -1741,7 +1741,7 @@ bool ASTScopeImpl::reexpandIfObsolete(ScopeCreator &scopeCreator) { ASTScopeAssert(getWasExpanded(), "Cannot be current if unexpanded."); return false; } - this->reexpand(scopeCreator); + reexpand(scopeCreator); return true; } @@ -1941,9 +1941,6 @@ TopLevelCodeScope::getParentOfASTAncestorScopesToBeRescued() { #pragma mark rescuing & reusing std::vector ASTScopeImpl::rescueASTAncestorScopesForReuseFromMeOrDescendants() { -// If I was never expanded, then there won't be any rescuable scopes. - if (!getWasExpanded()) - return {}; if (auto *p = getParentOfASTAncestorScopesToBeRescued().getPtrOrNull()) { return p->rescueASTAncestorScopesForReuseFromMe(); } @@ -1962,7 +1959,7 @@ void ASTScopeImpl::replaceASTAncestorScopes( } auto &ctx = getASTContext(); for (auto *s : scopesToAdd) { - p->addChild(s, ctx); // NONORGANIC + p->addChild(s, ctx); ASTScopeAssert(s->verifyThatThisNodeComeAfterItsPriorSibling(), "Ensure search will work"); } From 4166c397b12a11af2993262e525ce10d2eb2b621 Mon Sep 17 00:00:00 2001 From: David Ungar Date: Sun, 22 Sep 2019 17:48:30 -0700 Subject: [PATCH 165/199] Fix scope map test --- test/NameBinding/scope_map_top_level.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/NameBinding/scope_map_top_level.swift b/test/NameBinding/scope_map_top_level.swift index 7dc64dee40f80..ed59389d34b68 100644 --- a/test/NameBinding/scope_map_top_level.swift +++ b/test/NameBinding/scope_map_top_level.swift @@ -37,7 +37,7 @@ var i: Int = b.my_identity() // CHECK-EXPANDED-NEXT: `-BraceStmtScope {{.*}}, [8:1 - 21:28] // CHECK-EXPANDED-NEXT: `-GuardStmtScope {{.*}}, [8:1 - 21:28] // CHECK-EXPANDED-NEXT: |-ConditionalClauseScope, [8:7 - 8:22] index 0 -// CHECK-EXPANDED-NEXT: `-ConditionalClausePatternUseScope, [8:22 - 8:22] let b? +// CHECK-EXPANDED-NEXT: `-ConditionalClausePatternUseScope, [8:22 - 8:22] let b{{\??}} // CHECK-EXPANDED-NEXT: |-BraceStmtScope {{.*}}, [8:22 - 9:1] // CHECK-EXPANDED-NEXT: `-LookupParentDiversionScope, [9:1 - 21:28] // CHECK-EXPANDED-NEXT: |-AbstractFunctionDeclScope {{.*}}, [11:1 - 11:13] 'foo()' From 7d2203e016ce03343fea686e5528373c61226f35 Mon Sep 17 00:00:00 2001 From: David Ungar Date: Sun, 22 Sep 2019 11:29:42 -0700 Subject: [PATCH 166/199] Count AST ancestor scopes instead of children when last expanded --- lib/AST/ASTScopeCreation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index cfc693e41cbb3..7d4b08d752cf1 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -1750,7 +1750,7 @@ void ASTScopeImpl::reexpand(ScopeCreator &scopeCreator) { auto astAncestorScopes = rescueASTAncestorScopesForReuseFromMeOrDescendants(); disownDescendants(scopeCreator); // If the expansion recurses back into the tree for lookup, the ASTAncestor - // scopes will have already been rescued and won't be found! HERE + // scopes will have already been rescued and won't be found! expandAndBeCurrent(scopeCreator); replaceASTAncestorScopes(astAncestorScopes); } From 4a265a91d7d839d73a18316ff686018b6dcd5cba Mon Sep 17 00:00:00 2001 From: David Ungar Date: Sun, 22 Sep 2019 18:07:44 -0700 Subject: [PATCH 167/199] Turn on ASTScopes --- include/swift/Basic/LangOptions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index dde60dca3602f..74e80db3f05ad 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -246,7 +246,7 @@ namespace swift { /// Default is in \c ParseLangArgs /// /// This is a staging flag; eventually it will be removed. - bool EnableASTScopeLookup = false; + bool EnableASTScopeLookup = true; /// Someday, ASTScopeLookup will supplant lookup in the parser bool DisableParserLookup = false; From a033d2b8a224c70bfab20fb4d0df5427978f392c Mon Sep 17 00:00:00 2001 From: David Zarzycki Date: Mon, 23 Sep 2019 11:58:09 +0300 Subject: [PATCH 168/199] [AST] Fix debug typo --- include/swift/AST/ASTScope.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index b4b5566ff7819..30d1d91dfd952 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -43,10 +43,10 @@ /// \p message must be a string literal #define ASTScopeAssert(predicate, message) \ assert((predicate) && message \ - " Try compiling with '-disable-astScope-lookup'.") + " Try compiling with '-disable-astscope-lookup'.") #define ASTScope_unreachable(message) \ - llvm_unreachable(message " Try compiling with '-disable-astScope-lookup'.") + llvm_unreachable(message " Try compiling with '-disable-astscope-lookup'.") namespace swift { From 6f5e5e61f5fba80adb87dba0a35be72970fdcc20 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Mon, 23 Sep 2019 11:41:24 -0700 Subject: [PATCH 169/199] Fix no-asserts build. --- include/swift/SIL/InstructionUtils.h | 3 --- lib/SIL/InstructionUtils.cpp | 4 ---- 2 files changed, 7 deletions(-) diff --git a/include/swift/SIL/InstructionUtils.h b/include/swift/SIL/InstructionUtils.h index 23a5192c37d92..100b79c663175 100644 --- a/include/swift/SIL/InstructionUtils.h +++ b/include/swift/SIL/InstructionUtils.h @@ -155,13 +155,10 @@ struct PolymorphicBuiltinSpecializedOverloadInfo { SILType resultType; bool hasOutParam; -#ifndef NDEBUG private: bool isInitialized; public: -#endif - PolymorphicBuiltinSpecializedOverloadInfo() : builtinInfo(nullptr), staticOverloadIdentifier(), argTypes(), resultType(), hasOutParam(false), isInitialized(false) {} diff --git a/lib/SIL/InstructionUtils.cpp b/lib/SIL/InstructionUtils.cpp index 92d557ab85722..7e98cc3ee8a33 100644 --- a/lib/SIL/InstructionUtils.cpp +++ b/lib/SIL/InstructionUtils.cpp @@ -536,10 +536,8 @@ void swift::findClosuresForFunctionValue( bool PolymorphicBuiltinSpecializedOverloadInfo::init( SILFunction *fn, BuiltinValueKind builtinKind, ArrayRef oldOperandTypes, SILType oldResultType) { -#ifndef NDEBUG assert(!isInitialized && "Expected uninitialized info"); SWIFT_DEFER { isInitialized = true; }; -#endif if (!isPolymorphicBuiltin(builtinKind)) return false; @@ -608,10 +606,8 @@ bool PolymorphicBuiltinSpecializedOverloadInfo::init( } bool PolymorphicBuiltinSpecializedOverloadInfo::init(BuiltinInst *bi) { -#ifndef NDEBUG assert(!isInitialized && "Can not init twice?!"); SWIFT_DEFER { isInitialized = true; }; -#endif // First quickly make sure we have a /real/ BuiltinValueKind, not an intrinsic // or None. From b9046c6d0381b39ce3cb898f1541a6505f035a86 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Mon, 23 Sep 2019 10:57:09 -0700 Subject: [PATCH 170/199] [polymorphic-builtin] Rather than asserting in IRGen if we see a builtin that was not specialized, turn the builtin into a trap. I forgot about this part of the design when I was working on this. To ensure that the whole design works as expected, I included a small end-to-end test using an experimental design for simd that uses polymorphic builtins that test this functionally. NOTE: The experimental design is only intended to exercise the code functionally. rdar://48248417 --- lib/IRGen/GenBuiltin.cpp | 11 +- lib/SIL/SILVerifier.cpp | 4 - test/IRGen/polymorphic_builtins.swift | 50 +++ test/Inputs/polymorphic_builtins.swift | 441 ++++++++++++++++++++ test/Interpreter/polymorphic_builtins.swift | 98 +++++ 5 files changed, 597 insertions(+), 7 deletions(-) create mode 100644 test/IRGen/polymorphic_builtins.swift create mode 100644 test/Inputs/polymorphic_builtins.swift create mode 100644 test/Interpreter/polymorphic_builtins.swift diff --git a/lib/IRGen/GenBuiltin.cpp b/lib/IRGen/GenBuiltin.cpp index e3d3489eb5a36..a3ca1b1d07bdc 100644 --- a/lib/IRGen/GenBuiltin.cpp +++ b/lib/IRGen/GenBuiltin.cpp @@ -314,9 +314,14 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin, return out.add(v); \ } #define BUILTIN_BINARY_OPERATION_POLYMORPHIC(id, name, attrs) \ - assert(Builtin.ID != BuiltinValueKind::id && \ - "This builtin should never be seen by IRGen. It is invalid in " \ - "Lowered sil"); + if (Builtin.ID == BuiltinValueKind::id) { \ + /* This builtin must be guarded so that dynamically it is never called. */ \ + IGF.emitTrap("invalid use of polymorphic builtin", /*Unreachable*/ false); \ + auto returnValue = llvm::UndefValue::get(IGF.IGM.Int8PtrTy); \ + /* Consume the arguments of the builtin. */ \ + (void)args.claimAll(); \ + return out.add(returnValue); \ + } #define BUILTIN_RUNTIME_CALL(id, name, attrs) \ if (Builtin.ID == BuiltinValueKind::id) { \ diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp index ab0a1fc5bef68..9c6f9d4a1dd93 100644 --- a/lib/SIL/SILVerifier.cpp +++ b/lib/SIL/SILVerifier.cpp @@ -1654,10 +1654,6 @@ class SILVerifier : public SILVerifierBase { verifyLLVMIntrinsic(BI, BI->getIntrinsicInfo().ID); return; } - - require(BI->getModule().getStage() != SILStage::Lowered || - !isPolymorphicBuiltin(*BI->getBuiltinKind()), - "Polymorphic builtins are illegal in lowered SIL?!"); } void checkFunctionRefBaseInst(FunctionRefBaseInst *FRI) { diff --git a/test/IRGen/polymorphic_builtins.swift b/test/IRGen/polymorphic_builtins.swift new file mode 100644 index 0000000000000..cda952f90b9e0 --- /dev/null +++ b/test/IRGen/polymorphic_builtins.swift @@ -0,0 +1,50 @@ +// This line tests that IRGen is properly turning the unspecialized builtins +// into traps. +// +// RUN: %target-swift-frontend -emit-ir -parse-as-library -parse-stdlib %s | %FileCheck %s + +// Make sure we are not eliminating these builtins before IRGen runs. As part of +// the builtin's contract, we expect IRGen to convert them to traps, not +// anything before. +// +// RUN: %target-swift-frontend -emit-sil -parse-as-library -parse-stdlib %s | %FileCheck --check-prefix=SIL %s + +import Swift + +// SIL-LABEL: sil [transparent] [serialized] @$s20polymorphic_builtins11_isConcrete4typeSbxm_tlF : $@convention(thin) (@thick T.Type) -> Bool { +// SIL: builtin "isConcrete"({{%[0-9]*}} : $@thick T.Type) : $Builtin.Int1 +// SIL: // end sil function '$s20polymorphic_builtins11_isConcrete4typeSbxm_tlF' +@_transparent +public func _isConcrete(type: T.Type) -> Bool { + return Bool(_builtinBooleanLiteral: Builtin.isConcrete(type)) +} + +// SIL-LABEL: sil [transparent] [serialized] @$s20polymorphic_builtins41calleeAddVectorsGenericTransparentGuardedyxx_xtlF : $@convention(thin) (@in_guaranteed T, @in_guaranteed T) -> @out T { +// SIL: builtin "isConcrete"({{%[0-9]*}} : $@thick T.Type) : $Builtin.Int1 +// SIL: builtin "generic_add"( +// SIL: } // end sil function '$s20polymorphic_builtins41calleeAddVectorsGenericTransparentGuardedyxx_xtlF' + +// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @"$s20polymorphic_builtins41calleeAddVectorsGenericTransparentGuardedyxx_xtlF"( +// CHECK: br i1 false, label %[[CONCRETE_LABEL:[0-9][0-9]*]], label %[[NON_CONCRETE_LABEL:[0-9][0-9]*]] +// +// CHECK: