Files
swift-mirror/lib/AST/ExtInfo.cpp
Tim Kientzle 1d961ba22d Add #include "swift/Basic/Assertions.h" to a lot of source files
Although I don't plan to bring over new assertions wholesale
into the current qualification branch, it's entirely possible
that various minor changes in main will use the new assertions;
having this basic support in the release branch will simplify that.
(This is why I'm adding the includes as a separate pass from
rewriting the individual assertions)
2024-06-05 19:37:30 -07:00

193 lines
5.9 KiB
C++

//===--- ExtInfo.cpp - Extended information for function types ------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements ASTExtInfo, SILExtInfo and related classes.
//
//===----------------------------------------------------------------------===//
#include "swift/AST/ClangModuleLoader.h"
#include "swift/AST/ExtInfo.h"
#include "swift/Basic/Assertions.h"
#include "clang/AST/Type.h"
#include <optional>
namespace swift {
// MARK: - ClangTypeInfo
bool operator==(ClangTypeInfo lhs, ClangTypeInfo rhs) {
if (lhs.type == rhs.type)
return true;
if (lhs.type && rhs.type)
return lhs.type->getCanonicalTypeInternal() ==
rhs.type->getCanonicalTypeInternal();
return false;
}
bool operator!=(ClangTypeInfo lhs, ClangTypeInfo rhs) {
return !(lhs == rhs);
}
ClangTypeInfo ClangTypeInfo::getCanonical() const {
if (!type)
return ClangTypeInfo();
return ClangTypeInfo(type->getCanonicalTypeInternal().getTypePtr());
}
void ClangTypeInfo::printType(ClangModuleLoader *cml,
llvm::raw_ostream &os) const {
cml->printClangType(type, os);
}
void ClangTypeInfo::dump(llvm::raw_ostream &os,
const clang::ASTContext &ctx) const {
if (type) {
type->dump(os, ctx);
} else {
os << "<nullptr>";
}
}
// MARK: - UnexpectedClangTypeError
std::optional<UnexpectedClangTypeError>
UnexpectedClangTypeError::checkClangType(SILFunctionTypeRepresentation silRep,
const clang::Type *type,
bool expectNonnullForCOrBlock,
bool expectCanonical) {
#ifdef NDEBUG
return std::nullopt;
#else
bool isBlock = true;
switch (silRep) {
case SILFunctionTypeRepresentation::CXXMethod:
case SILFunctionTypeRepresentation::CFunctionPointer:
isBlock = false;
LLVM_FALLTHROUGH;
case SILFunctionTypeRepresentation::Block: {
if (!type) {
if (expectNonnullForCOrBlock)
return {{Kind::NullForCOrBlock, type}};
return std::nullopt;
}
if (expectCanonical && !type->isCanonicalUnqualified())
return {{Kind::NonCanonical, type}};
if (isBlock && !type->isBlockPointerType())
return {{Kind::NotBlockPointer, type}};
if (!isBlock && !(type->isFunctionPointerType()
|| type->isFunctionReferenceType()))
return {{Kind::NotFunctionPointerOrReference, type}};
return std::nullopt;
}
default: {
if (type)
return {{Kind::NonnullForNonCOrBlock, type}};
return std::nullopt;
}
}
#endif
}
void UnexpectedClangTypeError::dump() {
auto &e = llvm::errs();
using Kind = UnexpectedClangTypeError::Kind;
switch (errorKind) {
case Kind::NullForCOrBlock: {
e << "Expected non-null Clang type for @convention(c)/@convention(block)"
<< " function but found nullptr.\n";
return;
}
case Kind::NonnullForNonCOrBlock: {
e << ("Expected null Clang type for non-@convention(c),"
" non-@convention(block) function but found:\n");
type->dump();
return;
}
case Kind::NotBlockPointer: {
e << ("Expected block pointer type for @convention(block) function but"
" found:\n");
type->dump();
return;
}
case Kind::NotFunctionPointerOrReference: {
e << ("Expected function pointer/reference type for @convention(c) function"
" but found:\n");
type->dump();
return;
}
case Kind::NonCanonical: {
e << "Expected canonicalized Clang type but found:\n";
type->dump();
return;
}
}
llvm_unreachable("Unhandled case for UnexpectedClangTypeError");
}
// [NOTE: ExtInfo-Clang-type-invariant]
// At the SIL level, all @convention(c) and @convention(block) function types
// are expected to carry a ClangTypeInfo. This is not enforced at the AST level
// because we may synthesize types which are not convertible to Clang types.
// 1. Type errors: If we have a type error, we may end up generating (say) a
// @convention(c) function type that has an ErrorType as a parameter.
// 2. Bridging: The representation can change during bridging. For example, an
// @convention(swift) function can be bridged to an @convention(block)
// function. Since this happens during SILGen, we may see a "funny" type
// like @convention(c) () -> @convention(swift) () -> () at the AST level.
// MARK: - ASTExtInfoBuilder
void ASTExtInfoBuilder::checkInvariants() const {
// See [NOTE: ExtInfo-Clang-type-invariant]
if (auto error = UnexpectedClangTypeError::checkClangType(
getSILRepresentation(), clangTypeInfo.getType(), false, false)) {
error.value().dump();
llvm_unreachable("Ill-formed ASTExtInfoBuilder.");
}
}
// MARK: - ASTExtInfo
ASTExtInfo ASTExtInfoBuilder::build() const {
checkInvariants();
return ASTExtInfo(*this);
}
// MARK: - SILExtInfoBuilder
void SILExtInfoBuilder::checkInvariants() const {
// See [NOTE: ExtInfo-Clang-type-invariant]
// [FIXME: Clang-type-plumbing] Strengthen check when UseClangFunctionTypes
// is removed.
if (auto error = UnexpectedClangTypeError::checkClangType(
getRepresentation(), clangTypeInfo.getType(), false, true)) {
error.value().dump();
llvm_unreachable("Ill-formed SILExtInfoBuilder.");
}
}
SILExtInfo SILExtInfoBuilder::build() const {
checkInvariants();
return SILExtInfo(*this);
}
// MARK: - SILExtInfo
std::optional<UnexpectedClangTypeError> SILExtInfo::checkClangType() const {
return UnexpectedClangTypeError::checkClangType(
getRepresentation(), getClangTypeInfo().getType(), true, true);
}
} // end namespace swift