diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index c42f0b4c16bbc..03e424b7c91c5 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -2523,9 +2523,7 @@ class PatternBindingDecl final : public Decl, Pattern *Pat, Expr *E, DeclContext *Parent); - SourceLoc getStartLoc() const { - return StaticLoc.isValid() ? StaticLoc : VarLoc; - } + SourceLoc getStartLoc() const; SourceRange getSourceRange() const; unsigned getNumPatternEntries() const { @@ -8413,9 +8411,8 @@ class FuncDecl : public AbstractFunctionDecl { SourceLoc getStaticLoc() const { return StaticLoc; } SourceLoc getFuncLoc() const { return FuncLoc; } - SourceLoc getStartLoc() const { - return StaticLoc.isValid() ? StaticLoc : FuncLoc; - } + SourceLoc getStartLoc() const; + SourceLoc getEndLoc() const; SourceRange getSourceRange() const; TypeRepr *getResultTypeRepr() const { return FnRetType.getTypeRepr(); } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 866fa083f43a2..dd013c3bb6e58 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2528,6 +2528,19 @@ StringRef PatternBindingEntry::getInitStringRepresentation( return extractInlinableText(ctx, init, scratch); } +SourceLoc PatternBindingDecl::getStartLoc() const { + if (StaticLoc.isValid()) + return StaticLoc; + + if (VarLoc.isValid()) + return VarLoc; + + if (getPatternList().empty()) + return SourceLoc(); + + return getPatternList().front().getStartLoc(); +} + SourceRange PatternBindingDecl::getSourceRange() const { SourceLoc startLoc = getStartLoc(); SourceLoc endLoc = getPatternList().empty() @@ -10308,30 +10321,20 @@ SourceRange AbstractFunctionDecl::getSignatureSourceRange() const { if (isImplicit()) return SourceRange(); - SourceLoc endLoc; - - // name(parameter list...) async throws(E) + SourceRange thrownTypeRange; if (auto *typeRepr = getThrownTypeRepr()) - endLoc = typeRepr->getSourceRange().End; - if (endLoc.isInvalid()) - endLoc = getThrowsLoc(); - if (endLoc.isInvalid()) - endLoc = getAsyncLoc(); + thrownTypeRange = typeRepr->getSourceRange(); - if (endLoc.isInvalid()) - return getParameterListSourceRange(); - return SourceRange(getNameLoc(), endLoc); + // name(parameter list...) async throws(E) + return SourceRange::combine(getParameterListSourceRange(), getAsyncLoc(), + getThrowsLoc(), thrownTypeRange); } SourceRange AbstractFunctionDecl::getParameterListSourceRange() const { if (isImplicit()) return SourceRange(); - auto endLoc = getParameters()->getSourceRange().End; - if (endLoc.isInvalid()) - return getNameLoc(); - - return SourceRange(getNameLoc(), endLoc); + return SourceRange::combine(getNameLoc(), getParameters()->getSourceRange()); } std::optional AbstractFunctionDecl::getBodyFingerprint() const { @@ -11454,33 +11457,62 @@ DestructorDecl *DestructorDecl::getSuperDeinit() const { return nullptr; } -SourceRange FuncDecl::getSourceRange() const { - SourceLoc startLoc = getStartLoc(); +SourceLoc FuncDecl::getStartLoc() const { + if (StaticLoc) + return StaticLoc; - if (startLoc.isInvalid()) - return SourceRange(); + if (FuncLoc) + return FuncLoc; - if (getBodyKind() == BodyKind::Unparsed) - return { startLoc, BodyRange.End }; + auto nameLoc = getNameLoc(); + if (nameLoc) + return nameLoc; - SourceLoc endLoc = getOriginalBodySourceRange().End; - if (endLoc.isInvalid()) { - if (isa(this)) - return startLoc; + auto sigStart = getSignatureSourceRange().Start; + if (sigStart) + return sigStart; - if (getBodyKind() == BodyKind::Synthesize) - return SourceRange(); + auto resultTyStart = getResultTypeSourceRange().Start; + if (resultTyStart) + return resultTyStart; - endLoc = getGenericTrailingWhereClauseSourceRange().End; - } - if (endLoc.isInvalid()) - endLoc = getResultTypeSourceRange().End; - if (endLoc.isInvalid()) - endLoc = getSignatureSourceRange().End; - if (endLoc.isInvalid()) - endLoc = startLoc; + auto genericWhereStart = getGenericTrailingWhereClauseSourceRange().Start; + if (genericWhereStart) + return genericWhereStart; - return { startLoc, endLoc }; + auto bodyStart = getOriginalBodySourceRange().Start; + if (bodyStart) + return bodyStart; + + return SourceLoc(); +} + +SourceLoc FuncDecl::getEndLoc() const { + auto bodyEnd = getOriginalBodySourceRange().End; + if (bodyEnd) + return bodyEnd; + + auto genericWhereEnd = getGenericTrailingWhereClauseSourceRange().End; + if (genericWhereEnd) + return genericWhereEnd; + + auto resultTyEnd = getResultTypeSourceRange().End; + if (resultTyEnd) + return resultTyEnd; + + auto sigEnd = getSignatureSourceRange().End; + if (sigEnd) + return sigEnd; + + return getStartLoc(); +} + +SourceRange FuncDecl::getSourceRange() const { + SourceLoc startLoc = getStartLoc(); + if (startLoc.isInvalid()) + return SourceRange(); + + return { startLoc, getEndLoc() }; } EnumElementDecl::EnumElementDecl(SourceLoc IdentifierLoc, DeclName Name, diff --git a/lib/Basic/SourceLoc.cpp b/lib/Basic/SourceLoc.cpp index 03b9ce15f1823..ed3f9e2aa3160 100644 --- a/lib/Basic/SourceLoc.cpp +++ b/lib/Basic/SourceLoc.cpp @@ -482,7 +482,7 @@ namespace { std::optional SourceManager::findBufferContainingLocInternal(SourceLoc Loc) const { - assert(Loc.isValid()); + ASSERT(Loc.isValid()); // If the cache is out-of-date, update it now. unsigned numBuffers = LLVMSourceMgr.getNumBuffers(); diff --git a/lib/IDE/PostfixCompletion.cpp b/lib/IDE/PostfixCompletion.cpp index 02849e6b72980..7fbad08e902f2 100644 --- a/lib/IDE/PostfixCompletion.cpp +++ b/lib/IDE/PostfixCompletion.cpp @@ -110,9 +110,6 @@ getClosureActorIsolation(const Solution &S, AbstractClosureExpr *ACE) { if (auto Ty = target->getClosureContextualType()) return Ty; } - if (!S.hasType(E)) { - return Type(); - } return getTypeForCompletion(S, E); }; auto getClosureActorIsolationThunk = [&S](AbstractClosureExpr *ACE) { diff --git a/lib/IDE/TypeCheckCompletionCallback.cpp b/lib/IDE/TypeCheckCompletionCallback.cpp index e068312deee23..58406f9d8215c 100644 --- a/lib/IDE/TypeCheckCompletionCallback.cpp +++ b/lib/IDE/TypeCheckCompletionCallback.cpp @@ -58,7 +58,7 @@ Type swift::ide::getTypeForCompletion(const constraints::Solution &S, } if (!S.hasType(Node)) { - assert(false && "Expression wasn't type checked?"); + CONDITIONAL_ASSERT(false && "Expression wasn't type checked?"); return nullptr; } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 2294a70f66fbf..f962bad7f67e4 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -9009,7 +9009,7 @@ Parser::parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD) { auto bodyRange = AFD->getBodySourceRange(); auto BeginParserPosition = getParserPosition(bodyRange.Start, /*previousLoc*/ SourceLoc()); - auto EndLexerState = L->getStateForEndOfTokenLoc(AFD->getEndLoc()); + auto EndLexerState = L->getStateForEndOfTokenLoc(bodyRange.End); // ParserPositionRAII needs a primed parser to restore to. if (Tok.is(tok::NUM_TOKENS)) diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 65cd24d2fc60d..6b0ffdac82f14 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -3639,7 +3639,7 @@ Parser::parseExprCollectionElement(std::optional &isDictionary) { } else { diagnose(Tok, diag::expected_colon_in_dictionary_literal); Value = makeParserResult(makeParserError(), - new (Context) ErrorExpr(SourceRange())); + new (Context) ErrorExpr(PreviousLoc)); } // Make a tuple of Key Value pair. diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 343aa461aef54..c941cf404cc52 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -2462,12 +2462,29 @@ bool TypeCheckASTNodeAtLocRequest::evaluate( return MacroWalking::ArgumentsAndExpansion; } + /// Checks whether the given range, when treated as a character range, + /// contains the searched location. + bool charRangeContainsLoc(SourceRange range) { + if (!range) + return false; + + if (SM.isBefore(Loc, range.Start)) + return false; + + // NOTE: We need to check the character loc here because the target + // loc can be inside the last token of the node. i.e. interpolated + // string. + return SM.isBefore(Loc, Lexer::getLocForEndOfToken(SM, range.End)); + } + PreWalkResult walkToStmtPre(Stmt *S) override { if (auto *brace = dyn_cast(S)) { - auto braceCharRange = Lexer::getCharSourceRangeFromSourceRange( - SM, brace->getSourceRange()); + auto braceRange = brace->getSourceRange(); + auto braceCharRange = SourceRange( + braceRange.Start, Lexer::getLocForEndOfToken(SM, braceRange.End)); + // Unless this brace contains the loc, there's nothing to do. - if (!braceCharRange.contains(Loc)) + if (!SM.containsLoc(braceCharRange, Loc)) return Action::SkipNode(S); // Reset the node found in a parent context if it's not part of this @@ -2477,22 +2494,22 @@ bool TypeCheckASTNodeAtLocRequest::evaluate( // syntactically part of the brace stmt's range but won't be walked as // a child of the brace stmt. if (!brace->isImplicit() && FoundNode) { - auto foundNodeCharRange = Lexer::getCharSourceRangeFromSourceRange( - SM, FoundNode->getSourceRange()); - if (!braceCharRange.contains(foundNodeCharRange)) { + auto foundRange = FoundNode->getSourceRange(); + auto foundCharRange = SourceRange( + foundRange.Start, Lexer::getLocForEndOfToken(SM, foundRange.End)); + if (!SM.encloses(braceCharRange, foundCharRange)) FoundNode = nullptr; - } } for (ASTNode &node : brace->getElements()) { - if (SM.isBeforeInBuffer(Loc, node.getStartLoc())) + auto range = node.getSourceRange(); + if (SM.isBefore(Loc, range.Start)) break; // NOTE: We need to check the character loc here because the target // loc can be inside the last token of the node. i.e. interpolated // string. - SourceLoc endLoc = Lexer::getLocForEndOfToken(SM, node.getEndLoc()); - if (SM.isBeforeInBuffer(endLoc, Loc) || endLoc == Loc) + if (!SM.isBefore(Loc, Lexer::getLocForEndOfToken(SM, range.End))) continue; // 'node' may be the target node, except 'CaseStmt' which cannot be @@ -2509,13 +2526,11 @@ bool TypeCheckASTNodeAtLocRequest::evaluate( return Action::Stop(); } else if (auto Conditional = dyn_cast(S)) { for (StmtConditionElement &Cond : Conditional->getCond()) { - if (SM.isBeforeInBuffer(Loc, Cond.getStartLoc())) { + auto range = Cond.getSourceRange(); + if (SM.isBefore(Loc, range.Start)) break; - } - SourceLoc endLoc = Lexer::getLocForEndOfToken(SM, Cond.getEndLoc()); - if (SM.isBeforeInBuffer(endLoc, Loc) || endLoc == Loc) { + if (!SM.isBefore(Loc, Lexer::getLocForEndOfToken(SM, range.End))) continue; - } FoundNodeStorage = ASTNode(&Cond); FoundNode = &FoundNodeStorage; @@ -2527,11 +2542,7 @@ bool TypeCheckASTNodeAtLocRequest::evaluate( } PreWalkResult walkToExprPre(Expr *E) override { - if (SM.isBeforeInBuffer(Loc, E->getStartLoc())) - return Action::SkipNode(E); - - SourceLoc endLoc = Lexer::getLocForEndOfToken(SM, E->getEndLoc()); - if (SM.isBeforeInBuffer(endLoc, Loc)) + if (!charRangeContainsLoc(E->getSourceRange())) return Action::SkipNode(E); // Don't walk into 'TapExpr'. They should be type checked with parent @@ -2546,9 +2557,7 @@ bool TypeCheckASTNodeAtLocRequest::evaluate( if (auto *SVE = dyn_cast(E)) { SmallVector scratch; for (auto *result : SVE->getResultExprs(scratch)) { - auto resultCharRange = Lexer::getCharSourceRangeFromSourceRange( - SM, result->getSourceRange()); - if (resultCharRange.contains(Loc)) { + if (charRangeContainsLoc(result->getSourceRange())) { if (!result->walk(*this)) return Action::Stop(); @@ -2570,20 +2579,15 @@ bool TypeCheckASTNodeAtLocRequest::evaluate( } PreWalkAction walkToDeclPre(Decl *D) override { + if (!charRangeContainsLoc(D->getSourceRange())) + return Action::SkipNode(); + if (auto *newDC = dyn_cast(D)) DC = newDC; - if (!SM.isBeforeInBuffer(Loc, D->getStartLoc())) { - // NOTE: We need to check the character loc here because the target - // loc can be inside the last token of the node. i.e. interpolated - // string. - SourceLoc endLoc = Lexer::getLocForEndOfToken(SM, D->getEndLoc()); - if (!(SM.isBeforeInBuffer(endLoc, Loc) || endLoc == Loc)) { - if (!isa(D)) { - FoundNodeStorage = ASTNode(D); - FoundNode = &FoundNodeStorage; - } - } + if (!isa(D)) { + FoundNodeStorage = ASTNode(D); + FoundNode = &FoundNodeStorage; } return Action::Continue(); } diff --git a/test/Concurrency/async_main_resolution.swift b/test/Concurrency/async_main_resolution.swift index fbace4d1ff457..604ffeca8cebb 100644 --- a/test/Concurrency/async_main_resolution.swift +++ b/test/Concurrency/async_main_resolution.swift @@ -63,11 +63,11 @@ extension MainProtocol { #endif // CHECK-IS-SYNC-LABEL: "MyMain" interface_type="MyMain.Type" -// CHECK-IS-SYNC: (func_decl {{.*}}implicit "$main()" interface_type="(MyMain.Type) -> () -> ()" +// CHECK-IS-SYNC: (func_decl {{.*}}implicit range={{.*}} "$main()" interface_type="(MyMain.Type) -> () -> ()" // CHECK-IS-SYNC: (declref_expr implicit type="(MyMain.Type) -> () -> ()" // CHECK-IS-ASYNC-LABEL: "MyMain" interface_type="MyMain.Type" -// CHECK-IS-ASYNC: (func_decl {{.*}}implicit "$main()" interface_type="(MyMain.Type) -> () async -> ()" +// CHECK-IS-ASYNC: (func_decl {{.*}}implicit range={{.*}} "$main()" interface_type="(MyMain.Type) -> () async -> ()" // CHECK-IS-ASYNC: (declref_expr implicit type="(MyMain.Type) -> () async -> ()" // CHECK-IS-ERROR1: error: 'MyMain' is annotated with '@main' and must provide a main static function of type {{\(\) -> Void or \(\) throws -> Void|\(\) -> Void, \(\) throws -> Void, \(\) async -> Void, or \(\) async throws -> Void}} diff --git a/test/Concurrency/where_clause_main_resolution.swift b/test/Concurrency/where_clause_main_resolution.swift index 4caeb9c724e64..3c81370b7e3f0 100644 --- a/test/Concurrency/where_clause_main_resolution.swift +++ b/test/Concurrency/where_clause_main_resolution.swift @@ -25,19 +25,19 @@ protocol App { // CHECK-SAME: interface_type=" (Self.Type) -> () async -> ()" extension App where Configuration == Config1 { -// CHECK-CONFIG1: (func_decl {{.*}}implicit "$main()" interface_type="(MainType.Type) -> () -> ()" +// CHECK-CONFIG1: (func_decl {{.*}}implicit range=[{{.*}}:[[@LINE+20]]:1 - line:[[@LINE+20]]:1] "$main()" interface_type="(MainType.Type) -> () -> ()" // CHECK-CONFIG1: [[SOURCE_FILE]]:[[# @LINE+1 ]] static func main() { } } extension App where Configuration == Config2 { -// CHECK-CONFIG2: (func_decl {{.*}}implicit "$main()" interface_type="(MainType.Type) -> () async -> ()" +// CHECK-CONFIG2: (func_decl {{.*}}implicit range=[{{.*}}:[[@LINE+14]]:1 - line:[[@LINE+14]]:1] "$main()" interface_type="(MainType.Type) -> () async -> ()" // CHECK-CONFIG2: [[SOURCE_FILE]]:[[# @LINE+1 ]] static func main() async { } } extension App where Configuration == Config3 { -// CHECK-CONFIG3-ASYNC: (func_decl {{.*}}implicit "$main()" interface_type="(MainType.Type) -> () async -> ()" +// CHECK-CONFIG3-ASYNC: (func_decl {{.*}}implicit range=[{{.*}}:[[@LINE+8]]:1 - line:[[@LINE+8]]:1] "$main()" interface_type="(MainType.Type) -> () async -> ()" // CHECK-CONFIG3-ASYNC: [[SOURCE_FILE]]:[[DEFAULT_ASYNCHRONOUS_MAIN_LINE]] } diff --git a/test/attr/ApplicationMain/attr_main_throws.swift b/test/attr/ApplicationMain/attr_main_throws.swift index 959a0f21b8eec..df6493ed0679a 100644 --- a/test/attr/ApplicationMain/attr_main_throws.swift +++ b/test/attr/ApplicationMain/attr_main_throws.swift @@ -7,7 +7,7 @@ struct MyBase { } } -// CHECK-AST: (func_decl {{.*}} implicit "$main()" interface_type="(MyBase.Type) -> () throws -> ()" access=internal static +// CHECK-AST: (func_decl {{.*}} implicit range=[{{.*}}:[[@LINE-6]]:1 - line:[[@LINE-6]]:1] "$main()" interface_type="(MyBase.Type) -> () throws -> ()" access=internal static // CHECK-AST-NEXT: (parameter "self" {{.*}}) // CHECK-AST-NEXT: (parameter_list) // CHECK-AST-NEXT: (brace_stmt implicit diff --git a/test/expr/capture/top-level-guard.swift b/test/expr/capture/top-level-guard.swift index 154c5804dad97..c0b2d8f4d492d 100644 --- a/test/expr/capture/top-level-guard.swift +++ b/test/expr/capture/top-level-guard.swift @@ -39,7 +39,7 @@ let closureCapture: () -> Void = { [x] in } // CHECK-LABEL: (defer_stmt -// CHECK-NEXT: (func_decl{{.*}}implicit "$defer()" interface_type="() -> ()" access=fileprivate captures=(x) +// CHECK-NEXT: (func_decl{{.*}}implicit range={{.*}} "$defer()" interface_type="() -> ()" access=fileprivate captures=(x) defer { _ = x } diff --git a/validation-test/IDE/stress_tester_issues_fixed/pr-81028.swift b/validation-test/IDE/stress_tester_issues_fixed/pr-81028.swift new file mode 100644 index 0000000000000..b168fc6642c5e --- /dev/null +++ b/validation-test/IDE/stress_tester_issues_fixed/pr-81028.swift @@ -0,0 +1,9 @@ +// RUN: %batch-code-completion + +// Make sure we don't crash. +func foo(xs: [[Int]], ys: [Int]) { + for x in ys { + _ = xs.map{ $0.filter{ $0 == x } #^COMPLETE^# } + // COMPLETE: Begin completions + } +}