Use cached evaluator results when looking up function types.

Also improve the output for thrown error destinations in
parsable modes.
This commit is contained in:
Tony Allevato
2025-01-21 10:23:03 -05:00
parent 8df48e52ff
commit f249db3f85
7 changed files with 108 additions and 31 deletions

View File

@@ -1722,6 +1722,7 @@ public:
DeclName MemberName);
ProtocolDecl *getProtocol(DeclContext *dc) const;
std::optional<ProtocolDecl *> getCachedProtocol(DeclContext *dc) const;
TypeRepr *getProtocolTypeRepr() const { return TyR; }
DeclName getMemberName() const { return MemberName; }

View File

@@ -45,6 +45,11 @@ public:
/// needs to be inferred.
Type getExplicitCaughtType(ASTContext &ctx) const;
/// Returns the explicitly-specified type error that will be caught by this
/// catch node, or `nullopt` if it has not yet been computed. This should only
/// be used for dumping.
std::optional<Type> getCachedExplicitCaughtType(ASTContext &ctx) const;
friend llvm::hash_code hash_value(CatchNode catchNode) {
using llvm::hash_value;
return hash_value(catchNode.getOpaqueValue());

View File

@@ -3326,6 +3326,10 @@ public:
/// Get the decl for this value's opaque result type, if it has one.
OpaqueTypeDecl *getOpaqueResultTypeDecl() const;
/// Gets the decl for this value's opaque result type if it has already been
/// computed, or `nullopt` otherwise. This should only be used for dumping.
std::optional<OpaqueTypeDecl *> getCachedOpaqueResultTypeDecl() const;
/// Get the representative for this value's opaque result type, if it has one.
/// Returns a `TypeRepr` instead of an `OpaqueReturnTypeRepr` because 'some'
/// types might appear in one or more structural positions, e.g. (some P,
@@ -7769,6 +7773,10 @@ public:
/// Retrieves the thrown interface type.
Type getThrownInterfaceType() const;
/// Returns the thrown interface type of this function if it has already been
/// computed, otherwise `nullopt`. This should only be used for dumping.
std::optional<Type> getCachedThrownInterfaceType() const;
/// Retrieve the "effective" thrown interface type, or std::nullopt if
/// this function cannot throw.
///
@@ -8329,6 +8337,10 @@ public:
/// Retrieve the result interface type of this function.
Type getResultInterfaceType() const;
/// Returns the result interface type of this function if it has already been
/// computed, otherwise `nullopt`. This should only be used for dumping.
std::optional<Type> getCachedResultInterfaceType() const;
/// isUnaryOperator - Determine whether this is a unary operator
/// implementation. This check is a syntactic rather than type-based check,
/// which looks at the number of parameters specified, in order to allow
@@ -9529,6 +9541,10 @@ public:
/// Retrieve the interface type produced when expanding this macro.
Type getResultInterfaceType() const;
/// Returns the result interface type of this macro if it has already been
/// computed, otherwise `nullopt`. This should only be used for dumping.
std::optional<Type> getCachedResultInterfaceType() const;
/// Determine the contexts in which this macro can be applied.
MacroRoles getMacroRoles() const;

View File

@@ -1671,6 +1671,17 @@ namespace {
}
}
/// Prints a `Type` if it is present, falling back to the `TypeRepr`
/// otherwise (and lastly, doing nothing if the `TypeRepr` was also null).
void printTypeOrTypeRepr(std::optional<Type> Ty, TypeRepr *Repr,
Label label) {
if (Ty.has_value()) {
printTypeField(*Ty, label);
} else if (Repr) {
printRec(Repr, label);
}
}
void printThrowDest(ThrownErrorDestination throws, bool wantNothrow) {
if (!throws) {
if (wantNothrow)
@@ -1681,11 +1692,26 @@ namespace {
auto thrownError = throws.getThrownErrorType();
auto contextError = throws.getContextErrorType();
if (Writer.isParsable()) {
// For parsable outputs, just print the full thrown and contextual error
// information as a nice structured object, even if they're the same.
printRecArbitrary(
[&](Label label) {
printHead("thrown_error_destination", IdentifierColor, label);
printTypeField(thrownError, Label::always("thrown_type"));
printTypeField(contextError, Label::always("context_type"));
printFoot();
},
Label::always("throws"));
return;
}
if (thrownError->isEqual(contextError)) {
// No translation of the thrown error type is required, so ony print
// No translation of the thrown error type is required, so only print
// the thrown error type.
Type errorExistentialType =
contextError->getASTContext().getErrorExistentialType();
if (errorExistentialType && thrownError->isEqual(errorExistentialType))
printFlag("throws", ExprModifierColor);
else {
@@ -2456,29 +2482,20 @@ namespace {
if (auto *P = D->getImplicitSelfDecl()) {
printRec(P, Label::optional("implicit_self_decl"));
}
printRec(D->getParameters(), Label::optional("params"),
&D->getASTContext());
if (auto FD = dyn_cast<FuncDecl>(D)) {
if (Writer.isParsable() && FD->hasInterfaceType()) {
printTypeField(FD->getResultInterfaceType(), Label::always("result"));
if (auto opaque = FD->getOpaqueResultTypeDecl()) {
printRec(opaque, Label::always("opaque_result_decl"));
}
} else if (FD->getResultTypeRepr()) {
printRec(FD->getResultTypeRepr(), Label::always("result"));
if (auto opaque = FD->getOpaqueResultTypeDecl()) {
printRec(opaque, Label::always("opaque_result_decl"));
}
printTypeOrTypeRepr(FD->getCachedResultInterfaceType(),
FD->getResultTypeRepr(), Label::always("result"));
if (auto opaque = FD->getCachedOpaqueResultTypeDecl();
opaque && *opaque != nullptr) {
printRec(*opaque, Label::always("opaque_result_decl"));
}
}
if (Writer.isParsable() && D->hasInterfaceType()) {
printTypeField(D->getThrownInterfaceType(),
Label::always("thrown_type"));
} else if (auto thrownTypeRepr = D->getThrownTypeRepr()) {
printRec(thrownTypeRepr,Label::always("thrown_type"));
}
printTypeOrTypeRepr(D->getCachedThrownInterfaceType(),
D->getThrownTypeRepr(), Label::always("thrown_type"));
printRec(D->getParameters(), Label::optional("params"),
&D->getASTContext());
if (auto fac = D->getForeignAsyncConvention()) {
printRecArbitrary([&](Label label) {
@@ -2653,10 +2670,8 @@ namespace {
printAttributes(MD);
printRec(MD->getParameterList(), Label::optional("params"),
&MD->getASTContext());
if (Writer.isParsable() && MD->getResultInterfaceType())
printTypeField(MD->getResultInterfaceType(), Label::always("result"));
else if (MD->resultType.getTypeRepr())
printRec(MD->resultType.getTypeRepr(), Label::always("result"));
printTypeOrTypeRepr(MD->getCachedResultInterfaceType(),
MD->getResultTypeRepr(), Label::always("result"));
printRec(MD->definition, Label::always("definition"));
printFoot();
}
@@ -4861,10 +4876,12 @@ public:
}
void visitCustomAttr(CustomAttr *Attr, Label label) {
printCommon(Attr, "custom_attr", label);
if (Writer.isParsable())
printTypeField(Attr->getType(), Label::always("type"));
else
printTypeField(Attr->getType(), Label::always("type"));
if (!Writer.isParsable()) {
// The type has the semantic information we want for parsable outputs, so
// omit the `TypeRepr` there.
printRec(Attr->getTypeRepr(), Label::optional("type_repr"));
}
if (Attr->getArgs())
printRec(Attr->getArgs(), Label::optional("args"));
printFoot();
@@ -4925,8 +4942,11 @@ public:
void visitImplementsAttr(ImplementsAttr *Attr, Label label) {
printCommon(Attr, "implements_attr", label);
if (Writer.isParsable()) {
printFieldQuoted(declUSR(Attr->getProtocol(DC)),
Label::always("protocol"));
// Print the resolved protocol's USR in parsable outputs, not the
// TypeRepr.
if (auto PD = Attr->getCachedProtocol(DC); PD && *PD != nullptr) {
printFieldQuoted(declUSR(*PD), Label::always("protocol"));
}
} else {
printRec(Attr->getProtocolTypeRepr(), Label::always("protocol"));
}

View File

@@ -2734,6 +2734,14 @@ ProtocolDecl *ImplementsAttr::getProtocol(DeclContext *dc) const {
ImplementsAttrProtocolRequest{this, dc}, nullptr);
}
std::optional<ProtocolDecl *>
ImplementsAttr::getCachedProtocol(DeclContext *dc) const {
ImplementsAttrProtocolRequest request{this, dc};
if (dc->getASTContext().evaluator.hasCachedResult(request))
return getProtocol(dc);
return std::nullopt;
}
CustomAttr::CustomAttr(SourceLoc atLoc, SourceRange range, TypeExpr *type,
CustomAttributeInitializer *initContext,
ArgumentList *argList, bool implicit)

View File

@@ -1102,6 +1102,14 @@ Type AbstractFunctionDecl::getThrownInterfaceType() const {
return CatchNode(mutableThis).getExplicitCaughtType(getASTContext());
}
std::optional<Type> AbstractFunctionDecl::getCachedThrownInterfaceType() const {
if (!getThrownTypeRepr())
return ThrownType.getType();
auto mutableThis = const_cast<AbstractFunctionDecl *>(this);
return CatchNode(mutableThis).getCachedExplicitCaughtType(getASTContext());
}
std::optional<Type> AbstractFunctionDecl::getEffectiveThrownErrorType() const {
// FIXME: Only getters can have thrown error types right now, and DidSet
// has a cyclic reference if we try to get its interface type here. Find a
@@ -3934,6 +3942,12 @@ OpaqueTypeDecl *ValueDecl::getOpaqueResultTypeDecl() const {
nullptr);
}
std::optional<OpaqueTypeDecl *>
ValueDecl::getCachedOpaqueResultTypeDecl() const {
return OpaqueResultTypeRequest{const_cast<ValueDecl *>(this)}
.getCachedResult();
}
bool ValueDecl::isObjC() const {
ASTContext &ctx = getASTContext();
return evaluateOrDefault(ctx.evaluator,
@@ -10768,6 +10782,11 @@ Type FuncDecl::getResultInterfaceType() const {
return ErrorType::get(ctx);
}
std::optional<Type> FuncDecl::getCachedResultInterfaceType() const {
auto mutableThis = const_cast<FuncDecl *>(this);
return ResultTypeRequest{mutableThis}.getCachedResult();
}
bool FuncDecl::isUnaryOperator() const {
if (!isOperator())
return false;
@@ -11925,6 +11944,11 @@ Type MacroDecl::getResultInterfaceType() const {
return ErrorType::get(ctx);
}
std::optional<Type> MacroDecl::getCachedResultInterfaceType() const {
auto mutableThis = const_cast<MacroDecl *>(this);
return ResultTypeRequest{mutableThis}.getCachedResult();
}
SourceRange MacroDecl::getSourceRange() const {
SourceLoc endLoc = getNameLoc();
if (parameterList)
@@ -12355,6 +12379,11 @@ Type CatchNode::getExplicitCaughtType(ASTContext &ctx) const {
ctx.evaluator, ExplicitCaughtTypeRequest{&ctx, *this}, Type());
}
std::optional<Type>
CatchNode::getCachedExplicitCaughtType(ASTContext &ctx) const {
return ExplicitCaughtTypeRequest{&ctx, *this}.getCachedResult();
}
void swift::simple_display(llvm::raw_ostream &out, CatchNode catchNode) {
out << "catch node";
}

View File

@@ -13,10 +13,8 @@
// RUN: %target-swift-frontend -dump-ast %t/FileLib.swift -module-alias XLogging=AppleLogging -I %t > %t/result-ast.output
// RUN: %FileCheck %s -input-file %t/result-ast.output -check-prefix CHECK-AST
// CHECK-AST-NOT: bind="XLogging"
// CHECK-AST-NOT: module<XLogging>
// CHECK-AST-NOT: decl="XLogging"
// CHECK-AST: type_unqualified_ident id="XLogging" bind="AppleLogging"
// CHECK-AST: module<AppleLogging>
// CHECK-AST: decl="AppleLogging"