mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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)
193 lines
5.9 KiB
C++
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
|