Skip to content

[Sema] Build TRC for delayed functions bodies #39064

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions lib/Sema/TypeCheckAvailability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -916,6 +916,25 @@ void TypeChecker::buildTypeRefinementContextHierarchy(SourceFile &SF) {
}
}

void TypeChecker::buildTypeRefinementContextHierarchyDelayed(SourceFile &SF, AbstractFunctionDecl *AFD) {
// If there's no TRC for the file, we likely don't want this one either.
// RootTRC is not set when availability checking is disabled.
TypeRefinementContext *RootTRC = SF.getTypeRefinementContext();
if(!RootTRC)
return;

if (AFD->getBodyKind() != AbstractFunctionDecl::BodyKind::Unparsed)
return;

// Parse the function body.
AFD->getBody(/*canSynthesize=*/true);

// Build the refinement context for the function body.
ASTContext &Context = SF.getASTContext();
TypeRefinementContextBuilder Builder(RootTRC, Context);
Builder.build(AFD);
}

TypeRefinementContext *
TypeChecker::getOrBuildTypeRefinementContext(SourceFile *SF) {
TypeRefinementContext *TRC = SF->getTypeRefinementContext();
Expand Down
3 changes: 3 additions & 0 deletions lib/Sema/TypeChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,9 @@ static void typeCheckDelayedFunctions(SourceFile &SF) {
while (currentFunctionIdx < SF.DelayedFunctions.size()) {
auto *AFD = SF.DelayedFunctions[currentFunctionIdx];
assert(!AFD->getDeclContext()->isLocalContext());

TypeChecker::buildTypeRefinementContextHierarchyDelayed(SF, AFD);

(void) AFD->getTypecheckedBody();
++currentFunctionIdx;
}
Expand Down
4 changes: 4 additions & 0 deletions lib/Sema/TypeChecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -961,6 +961,10 @@ AvailabilityContext overApproximateAvailabilityAtLocation(
/// Walk the AST to build the hierarchy of TypeRefinementContexts
void buildTypeRefinementContextHierarchy(SourceFile &SF);

/// Walk the AST to complete the hierarchy of TypeRefinementContexts for
/// the delayed function body of \p AFD.
void buildTypeRefinementContextHierarchyDelayed(SourceFile &SF, AbstractFunctionDecl *AFD);

/// Build the hierarchy of TypeRefinementContexts for the entire
/// source file, if it has not already been built. Returns the root
/// TypeRefinementContext for the source file.
Expand Down
49 changes: 49 additions & 0 deletions test/Sema/availability_and_delayed_parsing.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/// Check for reliable availability checking in inlinable code even when
/// skipping some function bodies. rdar://82269657

// RUN: %target-swift-frontend -typecheck -dump-type-refinement-contexts %s -target x86_64-apple-macos10.10 2>&1 \
// RUN: | %FileCheck %s --check-prefixes TRC-API,TRC-INLINABLE,TRC-WITHTYPES,TRC-FULL
// RUN: %target-swift-frontend -typecheck -dump-type-refinement-contexts %s -target x86_64-apple-macos10.10 -experimental-skip-non-inlinable-function-bodies-without-types 2>&1 \
// RUN: | %FileCheck %s --check-prefixes TRC-API,TRC-INLINABLE,TRC-WITHTYPES,TRC-FULL-NOT
// RUN: %target-swift-frontend -typecheck -dump-type-refinement-contexts %s -target x86_64-apple-macos10.10 -experimental-skip-non-inlinable-function-bodies 2>&1 \
// RUN: | %FileCheck %s --check-prefixes TRC-API,TRC-INLINABLE,TRC-WITHTYPES-NOT,TRC-FULL-NOT
// RUN: %target-swift-frontend -typecheck -dump-type-refinement-contexts %s -target x86_64-apple-macos10.10 -experimental-skip-all-function-bodies 2>&1 \
// RUN: | %FileCheck %s --check-prefixes TRC-API,TRC-INLINABLE-NOT,TRC-WITHTYPES-NOT,TRC-FULL-NOT

// REQUIRES: OS=macosx

@available(macOS 10.12, *)
public func foo() { }
// TRC-API: (root versions=[10.10.0,+Inf)
// TRC-API: (decl versions=[10.12,+Inf) decl=foo()

@inlinable public func inlinableFunc() {
if #available(macOS 10.12, *) {
foo()
}
}
// TRC-INLINABLE: (condition_following_availability versions=[10.12,+Inf)
// TRC-INLINABLE: (if_then versions=[10.12,+Inf)
// TRC-INLINABLE-NOT-NOT: (condition_following_availability versions=[10.12,+Inf)
// TRC-INLINABLE-NOT-NOT: (if_then versions=[10.12,+Inf)

public func funcWithType() {
struct S {}
if #available(macOS 10.13, *) {
foo()
}
}
// TRC-WITHTYPES: (condition_following_availability versions=[10.13,+Inf)
// TRC-WITHTYPES: (if_then versions=[10.13,+Inf)
// TRC-WITHTYPES-NOT-NOT: (condition_following_availability versions=[10.13,+Inf)
// TRC-WITHTYPES-NOT-NOT: (if_then versions=[10.13,+Inf)

public func funcSkippable() {
if #available(macOS 10.14, *) {
foo()
}
}
// TRC-FULL: (condition_following_availability versions=[10.14,+Inf)
// TRC-FULL: (if_then versions=[10.14,+Inf)
// TRC-FULL-NOT-NOT: (condition_following_availability versions=[10.14,+Inf)
// TRC-FULL-NOT-NOT: (if_then versions=[10.14,+Inf)