mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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:
@@ -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; }
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user