Skip to content

Commit 75ea859

Browse files
authored
Merge pull request #1257 from swiftwasm/release/5.3
[pull] swiftwasm-release/5.3 from release/5.3
2 parents 9a345d6 + 5a77383 commit 75ea859

File tree

7 files changed

+221
-57
lines changed

7 files changed

+221
-57
lines changed

lib/Frontend/ModuleInterfaceLoader.cpp

Lines changed: 46 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -738,8 +738,52 @@ class ModuleInterfaceLoaderImpl {
738738
}
739739
}
740740

741-
// If we weren't able to open the file for any reason, including it not
742-
// existing, keep going.
741+
// [Note: ModuleInterfaceLoader-defer-to-SerializedModuleLoader]
742+
// If there's a module adjacent to the .swiftinterface that we can
743+
// _likely_ load (it validates OK and is up to date), bail early with
744+
// errc::not_supported, so the next (serialized) loader in the chain will
745+
// load it.
746+
// Alternately, if there's a .swiftmodule present but we can't even
747+
// read it (for whatever reason), we should let the other module loader
748+
// diagnose it.
749+
750+
if (shouldLoadAdjacentModule) {
751+
auto adjacentModuleBuffer = fs.getBufferForFile(modulePath);
752+
if (adjacentModuleBuffer) {
753+
if (serializedASTBufferIsUpToDate(modulePath, *adjacentModuleBuffer.get(),
754+
deps)) {
755+
LLVM_DEBUG(llvm::dbgs() << "Found up-to-date module at "
756+
<< modulePath
757+
<< "; deferring to serialized module loader\n");
758+
return std::make_error_code(std::errc::not_supported);
759+
} else if (isInResourceDir(modulePath) &&
760+
loadMode == ModuleLoadingMode::PreferSerialized) {
761+
// Special-case here: If we're loading a .swiftmodule from the resource
762+
// dir adjacent to the compiler, defer to the serialized loader instead
763+
// of falling back. This is mainly to support development of Swift,
764+
// where one might change the module format version but forget to
765+
// recompile the standard library. If that happens, don't fall back
766+
// and silently recompile the standard library -- instead, error like
767+
// we used to.
768+
LLVM_DEBUG(llvm::dbgs() << "Found out-of-date module in the "
769+
"resource-dir at "
770+
<< modulePath
771+
<< "; deferring to serialized module loader "
772+
"to diagnose\n");
773+
return std::make_error_code(std::errc::not_supported);
774+
} else {
775+
LLVM_DEBUG(llvm::dbgs() << "Found out-of-date module at "
776+
<< modulePath << "\n");
777+
rebuildInfo.setModuleKind(modulePath,
778+
ModuleRebuildInfo::ModuleKind::Normal);
779+
}
780+
} else if (adjacentModuleBuffer.getError() != notFoundError) {
781+
LLVM_DEBUG(llvm::dbgs() << "Found unreadable module at "
782+
<< modulePath
783+
<< "; deferring to serialized module loader\n");
784+
return std::make_error_code(std::errc::not_supported);
785+
}
786+
}
743787

744788
// If we have a prebuilt cache path, check that too if the interface comes
745789
// from the SDK.
@@ -766,53 +810,6 @@ class ModuleInterfaceLoaderImpl {
766810
}
767811
}
768812

769-
// [Note: ModuleInterfaceLoader-defer-to-SerializedModuleLoader]
770-
// Finally, if there's a module adjacent to the .swiftinterface that we can
771-
// _likely_ load (it validates OK and is up to date), bail early with
772-
// errc::not_supported, so the next (serialized) loader in the chain will
773-
// load it.
774-
// Alternately, if there's a .swiftmodule present but we can't even
775-
// read it (for whatever reason), we should let the other module loader
776-
// diagnose it.
777-
if (!shouldLoadAdjacentModule)
778-
return notFoundError;
779-
780-
auto adjacentModuleBuffer = fs.getBufferForFile(modulePath);
781-
if (adjacentModuleBuffer) {
782-
if (serializedASTBufferIsUpToDate(modulePath, *adjacentModuleBuffer.get(),
783-
deps)) {
784-
LLVM_DEBUG(llvm::dbgs() << "Found up-to-date module at "
785-
<< modulePath
786-
<< "; deferring to serialized module loader\n");
787-
return std::make_error_code(std::errc::not_supported);
788-
} else if (isInResourceDir(modulePath) &&
789-
loadMode == ModuleLoadingMode::PreferSerialized) {
790-
// Special-case here: If we're loading a .swiftmodule from the resource
791-
// dir adjacent to the compiler, defer to the serialized loader instead
792-
// of falling back. This is mainly to support development of Swift,
793-
// where one might change the module format version but forget to
794-
// recompile the standard library. If that happens, don't fall back
795-
// and silently recompile the standard library -- instead, error like
796-
// we used to.
797-
LLVM_DEBUG(llvm::dbgs() << "Found out-of-date module in the "
798-
"resource-dir at "
799-
<< modulePath
800-
<< "; deferring to serialized module loader "
801-
"to diagnose\n");
802-
return std::make_error_code(std::errc::not_supported);
803-
} else {
804-
LLVM_DEBUG(llvm::dbgs() << "Found out-of-date module at "
805-
<< modulePath << "\n");
806-
rebuildInfo.setModuleKind(modulePath,
807-
ModuleRebuildInfo::ModuleKind::Normal);
808-
}
809-
} else if (adjacentModuleBuffer.getError() != notFoundError) {
810-
LLVM_DEBUG(llvm::dbgs() << "Found unreadable module at "
811-
<< modulePath
812-
<< "; deferring to serialized module loader\n");
813-
return std::make_error_code(std::errc::not_supported);
814-
}
815-
816813
// Couldn't find an up-to-date .swiftmodule, will need to build module from
817814
// interface.
818815
return notFoundError;

lib/IDE/CodeCompletion.cpp

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6170,15 +6170,33 @@ void CodeCompletionCallbacksImpl::doneParsing() {
61706170
if (analyzedExpr->getEndLoc() != CodeCompleteTokenExpr->getLoc())
61716171
break;
61726172

6173-
// If the call expression doesn't have a type, infer it from the
6174-
// possible callee info.
61756173
Type resultTy = analyzedExpr->getType();
6176-
if (!resultTy) {
6177-
if (ContextInfo.getPossibleCallees().empty())
6178-
break;
6179-
auto calleeInfo = ContextInfo.getPossibleCallees()[0];
6180-
resultTy = calleeInfo.Type->getResult();
6181-
analyzedExpr->setType(resultTy);
6174+
// If the call expression doesn't have a type, fallback to:
6175+
if (!resultTy || resultTy->is<ErrorType>()) {
6176+
// 1) Try to type check removing CodeCompletionExpr from the call.
6177+
Expr *removedExpr = analyzedExpr;
6178+
removeCodeCompletionExpr(CurDeclContext->getASTContext(),
6179+
removedExpr);
6180+
ConcreteDeclRef referencedDecl;
6181+
auto optT = getTypeOfCompletionContextExpr(
6182+
CurDeclContext->getASTContext(), CurDeclContext,
6183+
CompletionTypeCheckKind::Normal, removedExpr, referencedDecl);
6184+
if (optT) {
6185+
resultTy = *optT;
6186+
analyzedExpr->setType(resultTy);
6187+
}
6188+
}
6189+
if (!resultTy || resultTy->is<ErrorType>()) {
6190+
// 2) Infer it from the possible callee info.
6191+
if (!ContextInfo.getPossibleCallees().empty()) {
6192+
auto calleeInfo = ContextInfo.getPossibleCallees()[0];
6193+
resultTy = calleeInfo.Type->getResult();
6194+
analyzedExpr->setType(resultTy);
6195+
}
6196+
}
6197+
if (!resultTy || resultTy->is<ErrorType>()) {
6198+
// 3) Give up providing postfix completions.
6199+
break;
61826200
}
61836201

61846202
auto &SM = CurDeclContext->getASTContext().SourceMgr;

lib/IDE/ExprContextAnalysis.cpp

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "ExprContextAnalysis.h"
1414
#include "swift/AST/ASTContext.h"
15+
#include "swift/AST/ASTVisitor.h"
1516
#include "swift/AST/ASTWalker.h"
1617
#include "swift/AST/Decl.h"
1718
#include "swift/AST/DeclContext.h"
@@ -194,6 +195,81 @@ Expr *swift::ide::findParsedExpr(const DeclContext *DC,
194195
return finder.get();
195196
}
196197

198+
//===----------------------------------------------------------------------===//
199+
// removeCodeCompletionExpr(ASTContext, Expr)
200+
//===----------------------------------------------------------------------===//
201+
202+
namespace {
203+
// TODO: Implement other expressions?
204+
class CCExprRemover: public ASTWalker, public ExprVisitor<CCExprRemover, Expr *> {
205+
ASTContext &Ctx;
206+
207+
public:
208+
bool Removed = false;
209+
210+
CCExprRemover(ASTContext &Ctx) : Ctx(Ctx) {}
211+
212+
Expr *visitCallExpr(CallExpr *E) {
213+
SourceLoc lParenLoc, rParenLoc;
214+
SmallVector<Identifier, 2> argLabels;
215+
SmallVector<SourceLoc, 2> argLabelLocs;
216+
SmallVector<Expr *, 2> args;
217+
SmallVector<TrailingClosure, 2> trailingClosures;
218+
bool removing = false;
219+
220+
if (auto paren = dyn_cast<ParenExpr>(E->getArg())) {
221+
if (isa<CodeCompletionExpr>(paren->getSubExpr())) {
222+
lParenLoc = paren->getLParenLoc();
223+
rParenLoc = paren->getRParenLoc();
224+
removing = true;
225+
}
226+
} else if (auto tuple = dyn_cast<TupleExpr>(E->getArg())) {
227+
lParenLoc = tuple->getLParenLoc();
228+
rParenLoc = tuple->getRParenLoc();
229+
for (unsigned i = 0, e = tuple->getNumElements(); i != e; ++i) {
230+
if (isa<CodeCompletionExpr>(tuple->getElement(i))) {
231+
removing = true;
232+
continue;
233+
}
234+
235+
if (i < E->getUnlabeledTrailingClosureIndex()) {
236+
// Normal arguments.
237+
argLabels.push_back(E->getArgumentLabels()[i]);
238+
argLabelLocs.push_back(E->getArgumentLabelLocs()[i]);
239+
args.push_back(tuple->getElement(i));
240+
} else {
241+
// Trailing closure arguments.
242+
trailingClosures.emplace_back(E->getArgumentLabels()[i],
243+
E->getArgumentLabelLocs()[i],
244+
tuple->getElement(i));
245+
}
246+
}
247+
}
248+
if (removing) {
249+
Removed = true;
250+
return CallExpr::create(Ctx, E->getFn(), lParenLoc, args, argLabels,
251+
argLabelLocs, rParenLoc, trailingClosures,
252+
E->isImplicit());
253+
}
254+
return E;
255+
}
256+
257+
Expr *visitExpr(Expr *E) {
258+
return E;
259+
}
260+
261+
std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
262+
return {true, visit(E)};
263+
}
264+
};
265+
}
266+
267+
bool swift::ide::removeCodeCompletionExpr(ASTContext &Ctx, Expr *&expr) {
268+
CCExprRemover remover(Ctx);
269+
expr = expr->walk(remover);
270+
return remover.Removed;
271+
}
272+
197273
//===----------------------------------------------------------------------===//
198274
// getReturnTypeFromContext(DeclContext)
199275
//===----------------------------------------------------------------------===//

lib/IDE/ExprContextAnalysis.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ void typeCheckContextUntil(DeclContext *DC, SourceLoc Loc);
3434
/// exact the same as \p TargetRange. Returns \c nullptr if not found.
3535
Expr *findParsedExpr(const DeclContext *DC, SourceRange TargetRange);
3636

37+
/// Remove \c CodeCompletionExpr from \p expr . Returns \c true if it actually
38+
/// mutated the expression.
39+
///
40+
/// NOTE: Currently, this only removes CodeCompletionExpr at call argument
41+
/// position.
42+
bool removeCodeCompletionExpr(ASTContext &Ctx, Expr *&expr);
43+
3744
/// Returns expected return type of the given decl context.
3845
/// \p DC should be an \c AbstractFunctionDecl or an \c AbstractClosureExpr.
3946
Type getReturnTypeFromContext(const DeclContext *DC);

test/IDE/complete_multiple_trailingclosure.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INIT_REQUIRED_NEWLINE_2 | %FileCheck %s -check-prefix=INIT_REQUIRED_NEWLINE_2
1414
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INIT_REQUIRED_SAMELINE_3 | %FileCheck %s -check-prefix=INIT_REQUIRED_SAMELINE_3
1515
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INIT_REQUIRED_NEWLINE_3 | %FileCheck %s -check-prefix=INIT_REQUIRED_NEWLINE_3
16+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INIT_FALLBACK_1 | %FileCheck %s -check-prefix=INIT_FALLBACK
17+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INIT_FALLBACK_2 | %FileCheck %s -check-prefix=INIT_FALLBACK
1618

1719
func globalFunc1(fn1: () -> Int, fn2: () -> String) {}
1820
func testGlobalFunc() {
@@ -184,3 +186,24 @@ func testOptionalInit() {
184186
// INIT_REQUIRED_NEWLINE_3-NOT: name=fn3
185187
// INIT_REQUIRED_NEWLINE_3: End completions
186188
}
189+
190+
struct MyStruct4<T> {
191+
init(arg1: Int = 0, arg2: () -> T) {}
192+
init(name: String, arg2: () -> String, arg3: () -> T) {}
193+
194+
func testStructMethod() {}
195+
}
196+
func testFallbackPostfix() {
197+
let _ = MyStruct4 {
198+
1
199+
} #^INIT_FALLBACK_1^#
200+
// INIT_FALLBACK: Begin completions, 2 items
201+
// INIT_FALLBACK-DAG: Decl[InstanceMethod]/CurrNominal: .testStructMethod()[#Void#];
202+
// INIT_FALLBACK-DAG: Keyword[self]/CurrNominal: .self[#MyStruct4<Int>#];
203+
// INIT_FALLBACK: End completions
204+
let _ = MyStruct4(name: "test") {
205+
""
206+
} arg3: {
207+
1
208+
} #^INIT_FALLBACK_2^#
209+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/// Test the loading order of module interfaces between the SDK and the
2+
/// prebuilt cache. The order should be:
3+
///
4+
/// 1. Local cache (not tested here)
5+
/// 2. Next to the swiftinterface file
6+
/// 3. Prebuilt-module cache
7+
8+
/// Create folders for a) our Swift module, b) the module cache, and c) a
9+
/// fake resource dir with a default prebuilt module cache inside.
10+
// RUN: %empty-directory(%t/MyModule.swiftmodule)
11+
// RUN: %empty-directory(%t/ModuleCache)
12+
// RUN: %empty-directory(%t/ResourceDir/%target-sdk-name/prebuilt-modules/MyModule.swiftmodule)
13+
14+
/// Define two sets of public API.
15+
// RUN: echo 'public func nextToSwiftinterface() {}' > %t/NextToSwiftinterface.swift
16+
// RUN: echo 'public func prebuiltModule() {}' > %t/PrebuiltModule.swift
17+
18+
/// Compile this into a module in the SDK.
19+
// RUN: %target-swift-frontend -emit-module %t/NextToSwiftinterface.swift -o %t/MyModule.swiftmodule/%target-cpu.swiftmodule -module-name MyModule -parse-stdlib -emit-module-interface-path %t/MyModule.swiftmodule/%target-cpu.swiftinterface
20+
21+
/// Also put a module with a different API into the default prebuilt cache under the same name.
22+
// RUN: %target-swift-frontend -emit-module %t/PrebuiltModule.swift -o %t/ResourceDir/%target-sdk-name/prebuilt-modules/MyModule.swiftmodule/%target-cpu.swiftmodule -module-name MyModule -parse-stdlib
23+
24+
/// Import this module and expect to use the swiftmodule next to the swiftinterface.
25+
// RUN: %target-swift-frontend -typecheck -resource-dir %t/ResourceDir -I %t %s -parse-stdlib -module-cache-path %t/ModuleCache -sdk %t -D FIRST_NEXT_TO_SWIFTINTERFACE
26+
27+
/// Remove the first swiftmodule and import again to use the prebuilt swiftmodule.
28+
// RUN: rm %t/MyModule.swiftmodule/%target-cpu.swiftmodule
29+
// RUN: %target-swift-frontend -typecheck -resource-dir %t/ResourceDir -I %t %s -parse-stdlib -module-cache-path %t/ModuleCache -sdk %t -D THEN_PREBUILT_MODULE
30+
31+
import MyModule
32+
33+
#if FIRST_NEXT_TO_SWIFTINTERFACE
34+
35+
nextToSwiftinterface()
36+
37+
#elseif THEN_PREBUILT_MODULE
38+
39+
prebuiltModule()
40+
41+
#endif

test/Syntax/round_trip_stdlib.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1+
// <rdar://problem/64269925> test/Syntax/round_trip_stdlib.swift is very slow on ASAN build
2+
// REQUIRES: no_asan
13
// RUN: %round-trip-syntax-test -d %swift_src_root/stdlib --swift-syntax-test %swift-syntax-test

0 commit comments

Comments
 (0)