diff --git a/include/swift/IDE/PostfixCompletion.h b/include/swift/IDE/PostfixCompletion.h index 0e7953b5baf50..b9bb8f62a4239 100644 --- a/include/swift/IDE/PostfixCompletion.h +++ b/include/swift/IDE/PostfixCompletion.h @@ -86,10 +86,6 @@ class PostfixCompletionCallback : public TypeCheckCompletionCallback { PostfixCompletionCallback(CodeCompletionExpr *CompletionExpr, DeclContext *DC) : CompletionExpr(CompletionExpr), DC(DC) {} - /// Typecheck the code completion expression in isolation, calling - /// \c sawSolution for each solution formed. - void fallbackTypeCheck(DeclContext *DC) override; - /// Deliver code completion results that were discoverd by \c sawSolution to /// \p Consumer. /// \param DotLoc If we are completing after a dot, the location of the dot, diff --git a/include/swift/IDE/TypeCheckCompletionCallback.h b/include/swift/IDE/TypeCheckCompletionCallback.h index 6bf5e3ad4e481..2d00e8453454a 100644 --- a/include/swift/IDE/TypeCheckCompletionCallback.h +++ b/include/swift/IDE/TypeCheckCompletionCallback.h @@ -59,10 +59,6 @@ class TypeCheckCompletionCallback { /// True if at least one solution was passed via the \c sawSolution /// callback. bool gotCallback() const { return GotCallback; } - - /// Typecheck the code completion expression in its outermost expression - /// context, calling \c sawSolution for each solution formed. - virtual void fallbackTypeCheck(DeclContext *DC); }; // MARK: - Utility functions for subclasses of TypeCheckCompletionCallback diff --git a/include/swift/Sema/CompletionContextFinder.h b/include/swift/Sema/CompletionContextFinder.h index 289f0eb59a4b5..89c9fb9da2045 100644 --- a/include/swift/Sema/CompletionContextFinder.h +++ b/include/swift/Sema/CompletionContextFinder.h @@ -25,22 +25,6 @@ class SyntacticElementTarget; } class CompletionContextFinder : public ASTWalker { - enum class ContextKind { - FallbackExpression, - StringInterpolation, - SingleStmtClosure, - MultiStmtClosure, - ErrorExpression - }; - - struct Context { - ContextKind Kind; - Expr *E; - }; - - /// Stack of all "interesting" contexts up to code completion expression. - llvm::SmallVector Contexts; - /// If we are completing inside an expression, the \c CodeCompletionExpr that /// represents the code completion token. @@ -49,44 +33,18 @@ class CompletionContextFinder : public ASTWalker { /// component. llvm::PointerUnion CompletionNode; - Expr *InitialExpr = nullptr; - DeclContext *InitialDC; - - /// Whether we're looking for any viable fallback expression. - bool ForFallback = false; - - /// Finder for fallback completion contexts within the outermost non-closure - /// context of the code completion expression's direct context. - CompletionContextFinder(DeclContext *completionDC) - : InitialDC(completionDC), ForFallback(true) { - while (auto *ACE = dyn_cast(InitialDC)) - InitialDC = ACE->getParent(); - InitialDC->walkContext(*this); - } - public: MacroWalking getMacroWalkingBehavior() const override { return MacroWalking::Arguments; } /// Finder for completion contexts within the provided SyntacticElementTarget. - CompletionContextFinder(constraints::SyntacticElementTarget target, - DeclContext *DC); - - static CompletionContextFinder forFallback(DeclContext *DC) { - return CompletionContextFinder(DC); - } + CompletionContextFinder(constraints::SyntacticElementTarget target); PreWalkResult walkToExprPre(Expr *E) override; - PostWalkResult walkToExprPost(Expr *E) override; - PreWalkAction walkToDeclPre(Decl *D) override; - bool locatedInStringInterpolation() const { - return hasContext(ContextKind::StringInterpolation); - } - bool hasCompletionExpr() const { return CompletionNode.dyn_cast() != nullptr; } @@ -114,28 +72,8 @@ class CompletionContextFinder : public ASTWalker { /// If we are completing in a key path, returns the index at which the key /// path has the code completion component. size_t getKeyPathCompletionComponentIndex() const; - - struct Fallback { - Expr *E; ///< The fallback expression. - DeclContext *DC; ///< The fallback expression's decl context. - bool SeparatePrecheck; ///< True if the fallback may require prechecking. - }; - - /// As a fallback sometimes its useful to not only type-check - /// code completion expression directly but instead add some - /// of the enclosing context e.g. when completion is an argument - /// to a call. - std::optional getFallbackCompletionExpr() const; - -private: - bool hasContext(ContextKind kind) const { - return llvm::find_if(Contexts, [&kind](const Context &currContext) { - return currContext.Kind == kind; - }) != Contexts.end(); - } }; - /// Returns \c true if \p range is valid and contains the IDE inspection /// target. This performs the underlying check based on \c CharSourceRange /// to make sure we correctly return \c true if the ide inspection target diff --git a/include/swift/Sema/IDETypeChecking.h b/include/swift/Sema/IDETypeChecking.h index ca0bc7cb6df1b..57a888fbcdea9 100644 --- a/include/swift/Sema/IDETypeChecking.h +++ b/include/swift/Sema/IDETypeChecking.h @@ -140,22 +140,6 @@ namespace swift { bool typeCheckASTNodeAtLoc(TypeCheckASTNodeAtLocContext TypeCheckCtx, SourceLoc TargetLoc); - /// Thunk around \c TypeChecker::typeCheckForCodeCompletion to make it - /// available to \c swift::ide. - /// Type check the given expression and provide results back to code - /// completion via specified callback. - /// - /// This method is designed to be used for code completion which means that - /// it doesn't mutate given expression, even if there is a single valid - /// solution, and constraint solver is allowed to produce partially correct - /// solutions. Such solutions can have any number of holes in them. - /// - /// \returns `true` if target was applicable and it was possible to infer - /// types for code completion, `false` otherwise. - bool typeCheckForCodeCompletion( - constraints::SyntacticElementTarget &target, bool needsPrecheck, - llvm::function_ref callback); - /// Thunk around \c TypeChecker::resolveDeclRefExpr to make it available to /// \c swift::ide Expr *resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *Context); diff --git a/lib/IDE/AfterPoundExprCompletion.cpp b/lib/IDE/AfterPoundExprCompletion.cpp index a97b1b55d7f36..b29ad36e15688 100644 --- a/lib/IDE/AfterPoundExprCompletion.cpp +++ b/lib/IDE/AfterPoundExprCompletion.cpp @@ -13,7 +13,6 @@ #include "swift/IDE/AfterPoundExprCompletion.h" #include "swift/IDE/CodeCompletion.h" #include "swift/IDE/CompletionLookup.h" -#include "swift/Sema/CompletionContextFinder.h" #include "swift/Sema/ConstraintSystem.h" #include "swift/Sema/IDETypeChecking.h" diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index 620fe0bd251e9..e6e3058f18474 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -1494,18 +1494,6 @@ void CodeCompletionCallbacksImpl::typeCheckWithLookup( TypeCheckASTNodeAtLocContext::declContext(CurDeclContext), CompletionLoc); } - - // This (hopefully) only happens in cases where the expression isn't - // typechecked during normal compilation either (e.g. member completion in a - // switch case where there control expression is invalid). Having normal - // typechecking still resolve even these cases would be beneficial for - // tooling in general though. - if (!Lookup.gotCallback()) { - if (Context.TypeCheckerOpts.DebugConstraintSolver) { - llvm::errs() << "--- Fallback typecheck for code completion ---\n"; - } - Lookup.fallbackTypeCheck(CurDeclContext); - } } void CodeCompletionCallbacksImpl::postfixCompletion(SourceLoc CompletionLoc, diff --git a/lib/IDE/ExprCompletion.cpp b/lib/IDE/ExprCompletion.cpp index f7eb47c15d3e1..334363f1dbff9 100644 --- a/lib/IDE/ExprCompletion.cpp +++ b/lib/IDE/ExprCompletion.cpp @@ -119,6 +119,12 @@ void ExprTypeCheckCompletionCallback::collectResults( UnifiedCanHandleAsync |= Result.IsInAsyncContext; } + // If we didn't find any results, at least try to collect unqualified results. + if (Results.empty()) { + Lookup.getValueCompletionsInDeclContext(CCLoc); + Lookup.getSelfTypeCompletionInDeclContext(CCLoc, /*isForDeclResult=*/false); + } + collectCompletionResults(CompletionCtx, Lookup, DC, UnifiedTypeContext, UnifiedCanHandleAsync); } diff --git a/lib/IDE/PostfixCompletion.cpp b/lib/IDE/PostfixCompletion.cpp index 21595201fda48..5f32233aa4632 100644 --- a/lib/IDE/PostfixCompletion.cpp +++ b/lib/IDE/PostfixCompletion.cpp @@ -10,11 +10,10 @@ // //===----------------------------------------------------------------------===// -#include "swift/Basic/Assertions.h" #include "swift/IDE/PostfixCompletion.h" +#include "swift/Basic/Assertions.h" #include "swift/IDE/CodeCompletion.h" #include "swift/IDE/CompletionLookup.h" -#include "swift/Sema/CompletionContextFinder.h" #include "swift/Sema/ConstraintSystem.h" #include "swift/Sema/IDETypeChecking.h" @@ -72,37 +71,6 @@ void PostfixCompletionCallback::addResult(const Result &Res) { Results.push_back(Res); } -void PostfixCompletionCallback::fallbackTypeCheck(DeclContext *DC) { - assert(!gotCallback()); - - // Default to checking the completion expression in isolation. - Expr *fallbackExpr = CompletionExpr; - DeclContext *fallbackDC = DC; - - auto finder = CompletionContextFinder::forFallback(DC); - if (finder.hasCompletionExpr()) { - if (auto fallback = finder.getFallbackCompletionExpr()) { - fallbackExpr = fallback->E; - fallbackDC = fallback->DC; - } - } - - if (isa(fallbackDC)) { - // If the expression is embedded in a closure, the constraint system tries - // to retrieve that closure's type, which will fail since we won't have - // generated any type variables for it. Thus, fallback type checking isn't - // available in this case. - return; - } - - SyntacticElementTarget completionTarget(fallbackExpr, fallbackDC, CTP_Unused, - Type(), - /*isDiscared=*/true); - - typeCheckForCodeCompletion(completionTarget, /*needsPrecheck*/ true, - [&](const Solution &S) { sawSolution(S); }); -} - static ActorIsolation getClosureActorIsolation(const Solution &S, AbstractClosureExpr *ACE) { auto getType = [&S](Expr *E) -> Type { diff --git a/lib/IDE/TypeCheckCompletionCallback.cpp b/lib/IDE/TypeCheckCompletionCallback.cpp index 58406f9d8215c..023b257244010 100644 --- a/lib/IDE/TypeCheckCompletionCallback.cpp +++ b/lib/IDE/TypeCheckCompletionCallback.cpp @@ -10,10 +10,9 @@ // //===----------------------------------------------------------------------===// -#include "swift/Basic/Assertions.h" #include "swift/IDE/TypeCheckCompletionCallback.h" +#include "swift/Basic/Assertions.h" #include "swift/IDE/CompletionLookup.h" -#include "swift/Sema/CompletionContextFinder.h" #include "swift/Sema/ConstraintSystem.h" #include "swift/Sema/IDETypeChecking.h" @@ -21,29 +20,6 @@ using namespace swift; using namespace swift::ide; using namespace swift::constraints; -void TypeCheckCompletionCallback::fallbackTypeCheck(DeclContext *DC) { - assert(!GotCallback); - - auto finder = CompletionContextFinder::forFallback(DC); - if (!finder.hasCompletionExpr()) - return; - - auto fallback = finder.getFallbackCompletionExpr(); - if (!fallback || isa(fallback->DC)) { - // If the expression is embedded in a closure, the constraint system tries - // to retrieve that closure's type, which will fail since we won't have - // generated any type variables for it. Thus, fallback type checking isn't - // available in this case. - return; - } - - SyntacticElementTarget completionTarget(fallback->E, fallback->DC, CTP_Unused, - Type(), - /*isDiscared=*/true); - typeCheckForCodeCompletion(completionTarget, /*needsPrecheck=*/true, - [&](const Solution &S) { sawSolution(S); }); -} - // MARK: - Utility functions for subclasses of TypeCheckCompletionCallback Type swift::ide::getTypeForCompletion(const constraints::Solution &S, diff --git a/lib/IDE/UnresolvedMemberCompletion.cpp b/lib/IDE/UnresolvedMemberCompletion.cpp index 978a3ca5c03c0..f92ae492f8237 100644 --- a/lib/IDE/UnresolvedMemberCompletion.cpp +++ b/lib/IDE/UnresolvedMemberCompletion.cpp @@ -10,11 +10,10 @@ // //===----------------------------------------------------------------------===// -#include "swift/Basic/Assertions.h" #include "swift/IDE/UnresolvedMemberCompletion.h" +#include "swift/Basic/Assertions.h" #include "swift/IDE/CodeCompletion.h" #include "swift/IDE/CompletionLookup.h" -#include "swift/Sema/CompletionContextFinder.h" #include "swift/Sema/ConstraintSystem.h" #include "swift/Sema/IDETypeChecking.h" diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index b6e94d0120d4b..dfcfa3252695a 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -1555,6 +1555,9 @@ Parser::parseExprPostfixSuffix(ParserResult Result, bool isExprBasic, if (!Tok.isAtStartOfLine() && Tok.is(tok::unknown)) { SourceLoc UnknownLoc = consumeToken(); SourceRange ErrorRange = Result.get()->getSourceRange(); + if (SourceMgr.rangeContainsIDEInspectionTarget(Lexer::getCharSourceRangeFromSourceRange(SourceMgr, ErrorRange))) { + continue; + } ErrorRange.widen(UnknownLoc); Result = makeParserResult(Result, new (Context) ErrorExpr(ErrorRange, Type(), diff --git a/lib/Sema/BuilderTransform.cpp b/lib/Sema/BuilderTransform.cpp index 5d9cd6a9b6a47..589903a3d3226 100644 --- a/lib/Sema/BuilderTransform.cpp +++ b/lib/Sema/BuilderTransform.cpp @@ -1007,7 +1007,7 @@ TypeChecker::applyResultBuilderBodyTransform(FuncDecl *func, Type builderType) { cs.Options |= ConstraintSystemFlags::ForCodeCompletion; cs.solveForCodeCompletion(solutions); - CompletionContextFinder analyzer(target, func->getDeclContext()); + CompletionContextFinder analyzer(target); if (analyzer.hasCompletion()) { filterSolutionsForCodeCompletion(solutions, analyzer); for (const auto &solution : solutions) { diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index d1791809bc69b..3b57ba719d670 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -4907,9 +4907,14 @@ bool ConstraintSystem::generateConstraints( return convertTypeLocator; }; - // Substitute type variables in for placeholder types. + if (convertType->hasError()) { + recordFix( + IgnoreInvalidASTNode::create(*this, convertTypeLocator)); + } + + // Substitute type variables in for placeholder and error types. convertType = convertType.transformRec([&](Type type) -> std::optional { - if (type->is()) { + if (isa(type.getPointer())) { return Type(createTypeVariable(getLocator(type), TVO_CanBindToNoEscape | TVO_PrefersSubtypeBinding | diff --git a/lib/Sema/CompletionContextFinder.cpp b/lib/Sema/CompletionContextFinder.cpp index b63acd6d4ad98..7dd7d6b3eaf1b 100644 --- a/lib/Sema/CompletionContextFinder.cpp +++ b/lib/Sema/CompletionContextFinder.cpp @@ -17,38 +17,15 @@ using namespace swift; using namespace constraints; -using Fallback = CompletionContextFinder::Fallback; CompletionContextFinder::CompletionContextFinder( - SyntacticElementTarget target, DeclContext *DC) - : InitialExpr(target.getAsExpr()), InitialDC(DC) { - assert(DC); + SyntacticElementTarget target) { target.walk(*this); } ASTWalker::PreWalkResult CompletionContextFinder::walkToExprPre(Expr *E) { - if (auto *closure = dyn_cast(E)) { - // NOTE: We're querying hasSingleExpressionBody before the single-expression - // body transform has happened, so this won't take e.g SingleValueStmtExprs - // into account. - Contexts.push_back({closure->hasSingleExpressionBody() - ? ContextKind::SingleStmtClosure - : ContextKind::MultiStmtClosure, - closure}); - } - - if (isa(E)) { - Contexts.push_back({ContextKind::StringInterpolation, E}); - } - - if (isa(E) || isa(E) || - isa(E)) { - Contexts.push_back({ContextKind::FallbackExpression, E}); - } - if (auto *Error = dyn_cast(E)) { - Contexts.push_back({ContextKind::ErrorExpression, E}); if (auto *OrigExpr = Error->getOriginalExpr()) { OrigExpr->walk(*this); if (hasCompletionExpr()) @@ -75,22 +52,7 @@ CompletionContextFinder::walkToExprPre(Expr *E) { return Action::Continue(E); } -ASTWalker::PostWalkResult -CompletionContextFinder::walkToExprPost(Expr *E) { - if (isa(E) || isa(E) || - isa(E) || isa(E) || isa(E) || - isa(E)) { - assert(Contexts.back().E == E); - Contexts.pop_back(); - } - return Action::Continue(E); -} - ASTWalker::PreWalkAction CompletionContextFinder::walkToDeclPre(Decl *D) { - // Look through any decl if we're looking for any viable fallback expression. - if (ForFallback) - return Action::Continue(); - // Otherwise, follow the same rule as the ConstraintSystem, where only // nested PatternBindingDecls are solved as part of the system. Local decls // are handled by TypeCheckASTNodeAtLocRequest. @@ -112,53 +74,6 @@ size_t CompletionContextFinder::getKeyPathCompletionComponentIndex() const { return ComponentIndex; } -std::optional -CompletionContextFinder::getFallbackCompletionExpr() const { - if (!hasCompletionExpr()) { - // Creating a fallback expression only makes sense if we are completing in - // an expression, not when we're completing in a key path. - return std::nullopt; - } - - std::optional fallback; - bool separatePrecheck = false; - DeclContext *fallbackDC = InitialDC; - - // Find the outermost fallback expression within the innermost error - // expression or multi-statement closure, keeping track of its decl context. - for (auto context : Contexts) { - switch (context.Kind) { - case ContextKind::StringInterpolation: - LLVM_FALLTHROUGH; - case ContextKind::FallbackExpression: - if (!fallback && context.E != InitialExpr) - fallback = Fallback{context.E, fallbackDC, separatePrecheck}; - continue; - - case ContextKind::SingleStmtClosure: - if (!fallback && context.E != InitialExpr) - fallback = Fallback{context.E, fallbackDC, separatePrecheck}; - fallbackDC = cast(context.E); - continue; - - case ContextKind::MultiStmtClosure: - fallbackDC = cast(context.E); - LLVM_FALLTHROUGH; - case ContextKind::ErrorExpression:; - fallback = std::nullopt; - separatePrecheck = true; - continue; - } - } - - if (fallback) - return fallback; - - if (getCompletionExpr() != InitialExpr) - return Fallback{getCompletionExpr(), fallbackDC, separatePrecheck}; - return std::nullopt; -} - bool swift::containsIDEInspectionTarget(SourceRange range, const SourceManager &SourceMgr) { if (range.isInvalid()) diff --git a/lib/Sema/TypeCheckCodeCompletion.cpp b/lib/Sema/TypeCheckCodeCompletion.cpp index 2728c88bc2187..a9edda330d98c 100644 --- a/lib/Sema/TypeCheckCodeCompletion.cpp +++ b/lib/Sema/TypeCheckCodeCompletion.cpp @@ -198,7 +198,7 @@ void TypeChecker::filterSolutionsForCodeCompletion( } bool TypeChecker::typeCheckForCodeCompletion( - SyntacticElementTarget &target, bool needsPrecheck, + SyntacticElementTarget &target, llvm::function_ref callback) { auto *DC = target.getDeclContext(); auto &Context = DC->getASTContext(); @@ -211,88 +211,32 @@ bool TypeChecker::typeCheckForCodeCompletion( return false; } - CompletionContextFinder contextAnalyzer(target, DC); + CompletionContextFinder contextAnalyzer(target); // If there was no completion expr (e.g. if the code completion location was // among tokens that were skipped over during parser error recovery) bail. if (!contextAnalyzer.hasCompletion()) return false; - if (needsPrecheck) { - // First, pre-check the expression, validating any types that occur in the - // expression and folding sequence expressions. - auto failedPreCheck = ConstraintSystem::preCheckTarget(target); - if (failedPreCheck) - return false; - } + ConstraintSystemOptions options; + options |= ConstraintSystemFlags::AllowFixes; + options |= ConstraintSystemFlags::SuppressDiagnostics; + options |= ConstraintSystemFlags::ForCodeCompletion; - enum class CompletionResult { Ok, NotApplicable, Fallback }; - - auto solveForCodeCompletion = - [&](SyntacticElementTarget &target) -> CompletionResult { - ConstraintSystemOptions options; - options |= ConstraintSystemFlags::AllowFixes; - options |= ConstraintSystemFlags::SuppressDiagnostics; - options |= ConstraintSystemFlags::ForCodeCompletion; - - ConstraintSystem cs(DC, options); - - llvm::SmallVector solutions; - - // If solve failed to generate constraints or with some other - // issue, we need to fallback to type-checking a sub-expression. - cs.setTargetFor(target.getAsExpr(), target); - if (!cs.solveForCodeCompletion(target, solutions)) - return CompletionResult::Fallback; - - // Similarly, if the type-check didn't produce any solutions, fall back - // to type-checking a sub-expression in isolation. - if (solutions.empty()) - return CompletionResult::Fallback; - - // FIXME: instead of filtering, expose the score and viability to clients. - // Remove solutions that skipped over/ignored the code completion point - // or that require fixes and have a score that is worse than the best. - filterSolutionsForCodeCompletion(solutions, contextAnalyzer); - - llvm::for_each(solutions, callback); - return CompletionResult::Ok; - }; + ConstraintSystem cs(DC, options); - switch (solveForCodeCompletion(target)) { - case CompletionResult::Ok: - return true; + llvm::SmallVector solutions; - case CompletionResult::NotApplicable: - return false; + cs.setTargetFor(target.getAsExpr(), target); + if (!cs.solveForCodeCompletion(target, solutions) || solutions.empty()) + return true; - case CompletionResult::Fallback: - break; - } + // FIXME: instead of filtering, expose the score and viability to clients. + // Remove solutions that skipped over/ignored the code completion point + // or that require fixes and have a score that is worse than the best. + filterSolutionsForCodeCompletion(solutions, contextAnalyzer); - // Determine the best subexpression to use based on the collected context - // of the code completion expression. - auto fallback = contextAnalyzer.getFallbackCompletionExpr(); - if (!fallback) { - return true; - } - if (isa(fallback->DC)) { - // If the expression is embedded in a closure, the constraint system tries - // to retrieve that closure's type, which will fail since we won't have - // generated any type variables for it. Thus, fallback type checking isn't - // available in this case. - return true; - } - if (auto *expr = target.getAsExpr()) { - assert(fallback->E != expr); - (void)expr; - } - SyntacticElementTarget completionTarget(fallback->E, fallback->DC, - CTP_Unused, - /*contextualType=*/Type(), - /*isDiscarded=*/true); - typeCheckForCodeCompletion(completionTarget, fallback->SeparatePrecheck, - callback); + llvm::for_each(solutions, callback); return true; } diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 143f61d94c2f7..e751324439a0c 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -451,11 +451,11 @@ TypeChecker::typeCheckTarget(SyntacticElementTarget &target, // special handling. Returns true if handled, in which case we've already // type-checked it for completion, and don't need the solution applied. if (Context.CompletionCallback && - typeCheckForCodeCompletion(target, /*needsPrecheck*/ false, - [&](const constraints::Solution &S) { - Context.CompletionCallback->sawSolution(S); - })) + typeCheckForCodeCompletion(target, [&](const constraints::Solution &S) { + Context.CompletionCallback->sawSolution(S); + })) { return std::nullopt; + } // Construct a constraint system from this expression. ConstraintSystemOptions csOptions = ConstraintSystemFlags::AllowFixes; diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index bff6cec1bee7e..68470d37fc4b8 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -1075,7 +1075,7 @@ class StmtChecker : public StmtVisitor { assert(TheFunc && "Should have bailed from pre-check if this is None"); Type ResultTy = TheFunc->getBodyResultType(); - if (!ResultTy || ResultTy->hasError()) + if (!ResultTy) return nullptr; if (!RS->hasResult()) { @@ -2672,7 +2672,8 @@ bool TypeCheckASTNodeAtLocRequest::evaluate( // apply the solution. // FIXME: We ought to see if we can do better in that case. if (auto *CE = DC->getInnermostClosureForCaptures()) { - if (CE->getBodyState() == ClosureExpr::BodyState::Parsed) { + if (CE->getBodyState() == ClosureExpr::BodyState::Parsed && + !typeCheckCtx.isForUnattachedNode()) { swift::typeCheckASTNodeAtLoc( TypeCheckASTNodeAtLocContext::declContext(CE->getParent()), CE->getLoc()); diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp index ce71f941035e3..8ac9ae78ab9c6 100644 --- a/lib/Sema/TypeChecker.cpp +++ b/lib/Sema/TypeChecker.cpp @@ -556,13 +556,6 @@ bool swift::typeCheckASTNodeAtLoc(TypeCheckASTNodeAtLocContext TypeCheckCtx, true); } -bool swift::typeCheckForCodeCompletion( - constraints::SyntacticElementTarget &target, bool needsPrecheck, - llvm::function_ref callback) { - return TypeChecker::typeCheckForCodeCompletion(target, needsPrecheck, - callback); -} - Expr *swift::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *Context) { return TypeChecker::resolveDeclRefExpr(UDRE, Context); diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index a3a3a115f6f0c..7e128e27b71c2 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -668,7 +668,7 @@ void filterSolutionsForCodeCompletion( /// \returns `true` if target was applicable and it was possible to infer /// types for code completion, `false` otherwise. bool typeCheckForCodeCompletion( - constraints::SyntacticElementTarget &target, bool needsPrecheck, + constraints::SyntacticElementTarget &target, llvm::function_ref callback); /// Check the key-path expression. diff --git a/test/AutoDiff/Sema/differentiable_attr_type_checking.swift b/test/AutoDiff/Sema/differentiable_attr_type_checking.swift index 98ff06879396e..3463e52804708 100644 --- a/test/AutoDiff/Sema/differentiable_attr_type_checking.swift +++ b/test/AutoDiff/Sema/differentiable_attr_type_checking.swift @@ -643,7 +643,7 @@ class Super: Differentiable { // "covariant 'Self' can only appear at the top level of method result type". // expected-error @+1 2 {{'TangentVector' is not a member type of type 'Self'}} func vjpDynamicSelfResult() -> (Self, (Self.TangentVector) -> Self.TangentVector) { - return (self, { $0 }) + return (self, { $0 }) // expected-error {{cannot infer type of closure parameter '$0' without a type annotation}} } } diff --git a/test/Parse/subscripting.swift b/test/Parse/subscripting.swift index d28c5e6f4ba78..93eece26ed7e7 100644 --- a/test/Parse/subscripting.swift +++ b/test/Parse/subscripting.swift @@ -142,7 +142,7 @@ struct A2 { subscript (i : Int) -> // expected-error{{expected subscripting element type}} { get { - return stored + return stored // expected-error {{cannot find 'stored' in scope}} } set { stored = newValue // expected-error{{cannot find 'stored' in scope}} diff --git a/test/SPI/implicit_spi_import.swift b/test/SPI/implicit_spi_import.swift index 21a504313f3e5..c10dee0443af0 100644 --- a/test/SPI/implicit_spi_import.swift +++ b/test/SPI/implicit_spi_import.swift @@ -95,7 +95,9 @@ import Lib public func useImplicit() -> _Klass { return _Klass() } // expected-error{{cannot use class '_Klass' here; it is an SPI imported from 'Lib'}} @_spi(core) -public func useSPICore() -> CoreStruct { return CoreStruct() } // expected-error{{cannot find type 'CoreStruct' in scope}} +public func useSPICore() -> CoreStruct { return CoreStruct() } +// expected-error@-1 {{cannot find type 'CoreStruct' in scope}} +// expected-error@-2 {{cannot find 'CoreStruct' in scope}} public func useMain() -> APIProtocol? { return nil } diff --git a/test/Sema/placeholder_type.swift b/test/Sema/placeholder_type.swift index 01834cc6392fc..e82b0de43f684 100644 --- a/test/Sema/placeholder_type.swift +++ b/test/Sema/placeholder_type.swift @@ -205,7 +205,7 @@ struct Just: Publisher { struct SetFailureType: Publisher {} extension Publisher { - func setFailureType(to: T.Type) -> SetFailureType { // expected-note 2 {{in call to function 'setFailureType(to:)'}} + func setFailureType(to: T.Type) -> SetFailureType { // expected-note 3 {{in call to function 'setFailureType(to:)'}} return .init() } } @@ -257,6 +257,8 @@ func mismatchedReturnTypes() -> _ { // expected-error {{type placeholder may not @available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *) func opaque() -> some _ { // expected-error {{type placeholder not allowed here}} return Just().setFailureType(to: _.self) + // expected-error@-1 {{type placeholder not allowed here}} + // expected-error@-2 {{generic parameter 'T' could not be inferred}} } enum EnumWithPlaceholders { diff --git a/test/decl/protocol/protocols.swift b/test/decl/protocol/protocols.swift index acbda964835ee..e8d3950d46648 100644 --- a/test/decl/protocol/protocols.swift +++ b/test/decl/protocol/protocols.swift @@ -423,12 +423,14 @@ protocol P1 { protocol P2 { } -struct X3 where T.Assoc : P2 {} +struct X3 where T.Assoc : P2 {} // expected-note {{'T' declared as parameter to type 'X3'}} struct X4 : P1 { // expected-error@-1 {{type 'X4' does not conform to protocol 'P1'}} // expected-note@-2 {{add stubs for conformance}} func getX1() -> X3 { return X3() } + // expected-error@-1 {{generic parameter 'T' could not be inferred}} + // expected-note@-2 {{explicitly specify the generic arguments to fix this issue}} } protocol ShouldntCrash { diff --git a/validation-test/IDE/crashers/1118c1956154924d.swift b/validation-test/IDE/crashers_fixed/1118c1956154924d.swift similarity index 67% rename from validation-test/IDE/crashers/1118c1956154924d.swift rename to validation-test/IDE/crashers_fixed/1118c1956154924d.swift index 4f6cec7f5be68..6309785a07117 100644 --- a/validation-test/IDE/crashers/1118c1956154924d.swift +++ b/validation-test/IDE/crashers_fixed/1118c1956154924d.swift @@ -1,3 +1,3 @@ // {"kind":"complete","signature":"swift::constraints::ConstraintSystem::assignFixedType(swift::TypeVariableType*, swift::Type, bool, bool)","signatureAssert":"Assertion failed: (!type->hasError() && \"Should not be assigning a type involving ErrorType!\"), function assignFixedType"} -// RUN: not --crash %target-swift-ide-test -code-completion -batch-code-completion -skip-filecheck -code-completion-diagnostics -source-filename %s +// RUN: %target-swift-ide-test -code-completion -batch-code-completion -skip-filecheck -code-completion-diagnostics -source-filename %s [ _""#^COMPLETE^# diff --git a/validation-test/IDE/crashers/63cae8d8f799869.swift b/validation-test/IDE/crashers_fixed/63cae8d8f799869.swift similarity index 53% rename from validation-test/IDE/crashers/63cae8d8f799869.swift rename to validation-test/IDE/crashers_fixed/63cae8d8f799869.swift index 0ac8f4ed938a8..c5c967c3ac3c9 100644 --- a/validation-test/IDE/crashers/63cae8d8f799869.swift +++ b/validation-test/IDE/crashers_fixed/63cae8d8f799869.swift @@ -1,5 +1,5 @@ // {"kind":"complete","original":"8d3b43e5","signature":"(anonymous namespace)::ConstraintWalker::walkToExprPost(swift::Expr*)"} -// RUN: not --crash %target-swift-ide-test -code-completion -batch-code-completion -skip-filecheck -code-completion-diagnostics -source-filename %s +// RUN: %target-swift-ide-test -code-completion -batch-code-completion -skip-filecheck -code-completion-diagnostics -source-filename %s [ switch { case ((\.a) #^^# diff --git a/validation-test/IDE/crashers/7b2825e90bfce47.swift b/validation-test/IDE/crashers_fixed/7b2825e90bfce47.swift similarity index 62% rename from validation-test/IDE/crashers/7b2825e90bfce47.swift rename to validation-test/IDE/crashers_fixed/7b2825e90bfce47.swift index 84df96813e0ed..0b015a60019e1 100644 --- a/validation-test/IDE/crashers/7b2825e90bfce47.swift +++ b/validation-test/IDE/crashers_fixed/7b2825e90bfce47.swift @@ -1,3 +1,3 @@ // {"kind":"complete","signature":"swift::SourceManager::findBufferContainingLocInternal(swift::SourceLoc) const","signatureAssert":"Assertion failed: (Loc.isValid()), function findBufferContainingLocInternal"} -// RUN: not --crash %target-swift-ide-test -code-completion -batch-code-completion -skip-filecheck -code-completion-diagnostics -source-filename %s +// RUN: %target-swift-ide-test -code-completion -batch-code-completion -skip-filecheck -code-completion-diagnostics -source-filename %s class a { lazy b: () = { answer {}#^^# diff --git a/validation-test/IDE/crashers/928f167118f85cf.swift b/validation-test/IDE/crashers_fixed/928f167118f85cf.swift similarity index 70% rename from validation-test/IDE/crashers/928f167118f85cf.swift rename to validation-test/IDE/crashers_fixed/928f167118f85cf.swift index dabd64b1a2404..5f9044dbcc58f 100644 --- a/validation-test/IDE/crashers/928f167118f85cf.swift +++ b/validation-test/IDE/crashers_fixed/928f167118f85cf.swift @@ -1,5 +1,5 @@ // {"kind":"complete","original":"7bbb1dc5","signature":"swift::TypeRepr::print(swift::ASTPrinter&, swift::PrintOptions const&, swift::optionset::OptionSet) const","signatureAssert":"Assertion failed: (false && \"Expression wasn't type checked?\"), function getTypeForCompletion"} -// RUN: not --crash %target-swift-ide-test -code-completion -batch-code-completion -skip-filecheck -code-completion-diagnostics -source-filename %s +// RUN: %target-swift-ide-test -code-completion -batch-code-completion -skip-filecheck -code-completion-diagnostics -source-filename %s a ? { init { b { extension }#^^# diff --git a/validation-test/IDE/crashers/a51bc03e2023ede5.swift b/validation-test/IDE/crashers_fixed/a51bc03e2023ede5.swift similarity index 69% rename from validation-test/IDE/crashers/a51bc03e2023ede5.swift rename to validation-test/IDE/crashers_fixed/a51bc03e2023ede5.swift index 9e77f6fead89d..7fd10ff61609f 100644 --- a/validation-test/IDE/crashers/a51bc03e2023ede5.swift +++ b/validation-test/IDE/crashers_fixed/a51bc03e2023ede5.swift @@ -1,3 +1,3 @@ // {"kind":"complete","signature":"swift::constraints::ConstraintSystem::buildDisjunctionForOptionalVsUnderlying(swift::Type, swift::Type, swift::constraints::ConstraintLocator*)","signatureAssert":"Assertion failed: (isa(Val) && \"cast() argument of incompatible type!\"), function cast"} -// RUN: not --crash %target-swift-ide-test -code-completion -batch-code-completion -skip-filecheck -code-completion-diagnostics -source-filename %s +// RUN: %target-swift-ide-test -code-completion -batch-code-completion -skip-filecheck -code-completion-diagnostics -source-filename %s class a {b: c! = b #^COMPLETE^# diff --git a/validation-test/IDE/crashers/e6f077eee83be8a7.swift b/validation-test/IDE/crashers_fixed/e6f077eee83be8a7.swift similarity index 61% rename from validation-test/IDE/crashers/e6f077eee83be8a7.swift rename to validation-test/IDE/crashers_fixed/e6f077eee83be8a7.swift index 78684094e2329..11afb7c433636 100644 --- a/validation-test/IDE/crashers/e6f077eee83be8a7.swift +++ b/validation-test/IDE/crashers_fixed/e6f077eee83be8a7.swift @@ -1,4 +1,4 @@ // {"kind":"complete","signature":"swift::constraints::ConstraintSystem::getType(swift::ASTNode) const","signatureAssert":"Assertion failed: (!node.isNull() && \"Expected non-null node\"), function hasType"} -// RUN: not --crash %target-swift-ide-test -code-completion -batch-code-completion -skip-filecheck -code-completion-diagnostics -source-filename %s +// RUN: %target-swift-ide-test -code-completion -batch-code-completion -skip-filecheck -code-completion-diagnostics -source-filename %s if case ( #a,#^COMPLETE^# is b diff --git a/validation-test/IDE/crashers/ebec93dfd96612ef.swift b/validation-test/IDE/crashers_fixed/ebec93dfd96612ef.swift similarity index 63% rename from validation-test/IDE/crashers/ebec93dfd96612ef.swift rename to validation-test/IDE/crashers_fixed/ebec93dfd96612ef.swift index 3d4c76129e5df..c26115b3ebd24 100644 --- a/validation-test/IDE/crashers/ebec93dfd96612ef.swift +++ b/validation-test/IDE/crashers_fixed/ebec93dfd96612ef.swift @@ -1,5 +1,5 @@ // {"kind":"complete","signature":"(anonymous namespace)::ConstraintWalker::walkToExprPost(swift::Expr*)","signatureAssert":"Assertion failed: (!ty->is() && \"Cannot have InOutType in a tuple\"), function TupleTypeElt"} -// RUN: not --crash %target-swift-ide-test -code-completion -batch-code-completion -skip-filecheck -code-completion-diagnostics -source-filename %s +// RUN: %target-swift-ide-test -code-completion -batch-code-completion -skip-filecheck -code-completion-diagnostics -source-filename %s -switch { case < (&a diff --git a/validation-test/compiler_crashers_2_fixed/issue-52031.swift b/validation-test/compiler_crashers_2_fixed/issue-52031.swift index c8d96d07ce501..02b29a9299135 100644 --- a/validation-test/compiler_crashers_2_fixed/issue-52031.swift +++ b/validation-test/compiler_crashers_2_fixed/issue-52031.swift @@ -16,5 +16,6 @@ extension S: P where N: P { // expected-error@-3 {{'A' is not a member type of type 'X'}} // expected-error@-4 {{'A' is not a member type of type 'X'}} return S() + // expected-error@-1 {{'A' is not a member type of type 'X'}} } }