blob: fc883e6d32651016a66cb779632975e1298f2bd0 [file] [log] [blame]
//===--- TypeChecker.cpp - Type Checking ----------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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 the swift::performTypeChecking entry point for
// semantic analysis.
//
//===----------------------------------------------------------------------===//
#include "swift/Subsystems.h"
#include "TypeChecker.h"
#include "TypeCheckObjC.h"
#include "TypeCheckType.h"
#include "CodeSynthesis.h"
#include "MiscDiagnostics.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/ASTVisitor.h"
#include "swift/AST/Attr.h"
#include "swift/AST/DiagnosticSuppression.h"
#include "swift/AST/ExistentialLayout.h"
#include "swift/AST/Identifier.h"
#include "swift/AST/ImportCache.h"
#include "swift/AST/Initializer.h"
#include "swift/AST/ModuleLoader.h"
#include "swift/AST/NameLookup.h"
#include "swift/AST/PrettyStackTrace.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/SourceFile.h"
#include "swift/Basic/Statistic.h"
#include "swift/Basic/STLExtras.h"
#include "swift/Basic/Timer.h"
#include "swift/Parse/Lexer.h"
#include "swift/Sema/IDETypeChecking.h"
#include "swift/Strings.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/ADT/Twine.h"
#include <algorithm>
using namespace swift;
TypeChecker &TypeChecker::createForContext(ASTContext &ctx) {
(void)ctx.createLazyResolverIfMissing<TypeChecker>();
return *static_cast<TypeChecker *>(ctx.getLazyResolver());
}
TypeChecker::TypeChecker(ASTContext &Ctx)
: Context(Ctx), Diags(Ctx.Diags) {}
TypeChecker::~TypeChecker() {}
ProtocolDecl *TypeChecker::getProtocol(SourceLoc loc, KnownProtocolKind kind) {
auto protocol = Context.getProtocol(kind);
if (!protocol && loc.isValid()) {
diagnose(loc, diag::missing_protocol,
Context.getIdentifier(getProtocolName(kind)));
}
if (protocol && !protocol->getInterfaceType()) {
if (protocol->isInvalid())
return nullptr;
}
return protocol;
}
ProtocolDecl *TypeChecker::getLiteralProtocol(Expr *expr) {
if (isa<ArrayExpr>(expr))
return getProtocol(expr->getLoc(),
KnownProtocolKind::ExpressibleByArrayLiteral);
if (isa<DictionaryExpr>(expr))
return getProtocol(expr->getLoc(),
KnownProtocolKind::ExpressibleByDictionaryLiteral);
if (!isa<LiteralExpr>(expr))
return nullptr;
if (isa<NilLiteralExpr>(expr))
return getProtocol(expr->getLoc(),
KnownProtocolKind::ExpressibleByNilLiteral);
if (isa<IntegerLiteralExpr>(expr))
return getProtocol(expr->getLoc(),
KnownProtocolKind::ExpressibleByIntegerLiteral);
if (isa<FloatLiteralExpr>(expr))
return getProtocol(expr->getLoc(),
KnownProtocolKind::ExpressibleByFloatLiteral);
if (isa<BooleanLiteralExpr>(expr))
return getProtocol(expr->getLoc(),
KnownProtocolKind::ExpressibleByBooleanLiteral);
if (const auto *SLE = dyn_cast<StringLiteralExpr>(expr)) {
if (SLE->isSingleUnicodeScalar())
return getProtocol(
expr->getLoc(),
KnownProtocolKind::ExpressibleByUnicodeScalarLiteral);
if (SLE->isSingleExtendedGraphemeCluster())
return getProtocol(
expr->getLoc(),
KnownProtocolKind::ExpressibleByExtendedGraphemeClusterLiteral);
return getProtocol(expr->getLoc(),
KnownProtocolKind::ExpressibleByStringLiteral);
}
if (isa<InterpolatedStringLiteralExpr>(expr))
return getProtocol(expr->getLoc(),
KnownProtocolKind::ExpressibleByStringInterpolation);
if (auto E = dyn_cast<MagicIdentifierLiteralExpr>(expr)) {
switch (E->getKind()) {
case MagicIdentifierLiteralExpr::File:
case MagicIdentifierLiteralExpr::Function:
return getProtocol(expr->getLoc(),
KnownProtocolKind::ExpressibleByStringLiteral);
case MagicIdentifierLiteralExpr::Line:
case MagicIdentifierLiteralExpr::Column:
return getProtocol(expr->getLoc(),
KnownProtocolKind::ExpressibleByIntegerLiteral);
case MagicIdentifierLiteralExpr::DSOHandle:
return nullptr;
}
}
if (auto E = dyn_cast<ObjectLiteralExpr>(expr)) {
switch (E->getLiteralKind()) {
#define POUND_OBJECT_LITERAL(Name, Desc, Protocol)\
case ObjectLiteralExpr::Name:\
return getProtocol(expr->getLoc(), KnownProtocolKind::Protocol);
#include "swift/Syntax/TokenKinds.def"
}
}
return nullptr;
}
DeclName TypeChecker::getObjectLiteralConstructorName(ObjectLiteralExpr *expr) {
switch (expr->getLiteralKind()) {
case ObjectLiteralExpr::colorLiteral: {
return DeclName(Context, DeclBaseName::createConstructor(),
{ Context.getIdentifier("_colorLiteralRed"),
Context.getIdentifier("green"),
Context.getIdentifier("blue"),
Context.getIdentifier("alpha") });
}
case ObjectLiteralExpr::imageLiteral: {
return DeclName(Context, DeclBaseName::createConstructor(),
{ Context.getIdentifier("imageLiteralResourceName") });
}
case ObjectLiteralExpr::fileLiteral: {
return DeclName(Context, DeclBaseName::createConstructor(),
{ Context.getIdentifier("fileReferenceLiteralResourceName") });
}
}
llvm_unreachable("unknown literal constructor");
}
/// Return an idealized form of the parameter type of the given
/// object-literal initializer. This removes references to the protocol
/// name from the first argument label, which would be otherwise be
/// redundant when writing out the object-literal syntax:
///
/// #fileLiteral(fileReferenceLiteralResourceName: "hello.jpg")
///
/// Doing this allows us to preserve a nicer (and source-compatible)
/// literal syntax while still giving the initializer a semantically
/// unambiguous name.
Type TypeChecker::getObjectLiteralParameterType(ObjectLiteralExpr *expr,
ConstructorDecl *ctor) {
auto params = ctor->getMethodInterfaceType()
->castTo<FunctionType>()->getParams();
SmallVector<AnyFunctionType::Param, 8> newParams;
newParams.append(params.begin(), params.end());
auto replace = [&](StringRef replacement) -> Type {
newParams[0] = AnyFunctionType::Param(newParams[0].getPlainType(),
Context.getIdentifier(replacement),
newParams[0].getParameterFlags());
return AnyFunctionType::composeInput(Context, newParams,
/*canonicalVararg=*/false);
};
switch (expr->getLiteralKind()) {
case ObjectLiteralExpr::colorLiteral:
return replace("red");
case ObjectLiteralExpr::fileLiteral:
case ObjectLiteralExpr::imageLiteral:
return replace("resourceName");
}
llvm_unreachable("unknown literal constructor");
}
ModuleDecl *TypeChecker::getStdlibModule(const DeclContext *dc) {
if (auto *stdlib = Context.getStdlibModule()) {
return stdlib;
}
return dc->getParentModule();
}
/// Bind the given extension to the given nominal type.
static void bindExtensionToNominal(ExtensionDecl *ext,
NominalTypeDecl *nominal) {
if (ext->alreadyBoundToNominal())
return;
nominal->addExtension(ext);
}
static void bindExtensions(SourceFile &SF) {
// Utility function to try and resolve the extended type without diagnosing.
// If we succeed, we go ahead and bind the extension. Otherwise, return false.
auto tryBindExtension = [&](ExtensionDecl *ext) -> bool {
assert(!ext->canNeverBeBound() &&
"Only extensions that can ever be bound get here.");
if (auto nominal = ext->computeExtendedNominal()) {
bindExtensionToNominal(ext, nominal);
return true;
}
return false;
};
// Phase 1 - try to bind each extension, adding those whose type cannot be
// resolved to a worklist.
SmallVector<ExtensionDecl *, 8> worklist;
// FIXME: The current source file needs to be handled specially, because of
// private extensions.
for (auto import : namelookup::getAllImports(&SF)) {
// FIXME: Respect the access path?
for (auto file : import.second->getFiles()) {
auto SF = dyn_cast<SourceFile>(file);
if (!SF)
continue;
for (auto D : SF->Decls) {
if (auto ED = dyn_cast<ExtensionDecl>(D))
if (!tryBindExtension(ED))
worklist.push_back(ED);
}
}
}
// Phase 2 - repeatedly go through the worklist and attempt to bind each
// extension there, removing it from the worklist if we succeed.
bool changed;
do {
changed = false;
auto last = std::remove_if(worklist.begin(), worklist.end(),
tryBindExtension);
if (last != worklist.end()) {
worklist.erase(last, worklist.end());
changed = true;
}
} while(changed);
// Any remaining extensions are invalid. They will be diagnosed later by
// typeCheckDecl().
}
static void typeCheckFunctionsAndExternalDecls(SourceFile &SF, TypeChecker &TC) {
unsigned currentFunctionIdx = 0;
unsigned currentSynthesizedDecl = SF.LastCheckedSynthesizedDecl;
do {
// Type check conformance contexts.
for (unsigned i = 0; i != TC.ConformanceContexts.size(); ++i) {
auto decl = TC.ConformanceContexts[i];
if (auto *ext = dyn_cast<ExtensionDecl>(decl))
TC.checkConformancesInContext(ext, ext);
else {
auto *ntd = cast<NominalTypeDecl>(decl);
TC.checkConformancesInContext(ntd, ntd);
// Finally, we can check classes for missing initializers.
if (auto *classDecl = dyn_cast<ClassDecl>(ntd))
TC.maybeDiagnoseClassWithoutInitializers(classDecl);
}
}
TC.ConformanceContexts.clear();
// Type check the body of each of the function in turn. Note that outside
// functions must be visited before nested functions for type-checking to
// work correctly.
for (unsigned n = TC.definedFunctions.size(); currentFunctionIdx != n;
++currentFunctionIdx) {
auto *AFD = TC.definedFunctions[currentFunctionIdx];
assert(!AFD->getDeclContext()->isLocalContext());
TC.typeCheckAbstractFunctionBody(AFD);
}
// Type check synthesized functions and their bodies.
for (unsigned n = SF.SynthesizedDecls.size();
currentSynthesizedDecl != n;
++currentSynthesizedDecl) {
auto decl = SF.SynthesizedDecls[currentSynthesizedDecl];
TC.typeCheckDecl(decl);
}
} while (currentFunctionIdx < TC.definedFunctions.size() ||
currentSynthesizedDecl < SF.SynthesizedDecls.size() ||
!TC.ConformanceContexts.empty());
// FIXME: Horrible hack. Store this somewhere more appropriate.
SF.LastCheckedSynthesizedDecl = currentSynthesizedDecl;
// Compute captures for functions and closures we visited.
for (auto *closure : TC.ClosuresWithUncomputedCaptures) {
TypeChecker::computeCaptures(closure);
}
TC.ClosuresWithUncomputedCaptures.clear();
for (AbstractFunctionDecl *FD : llvm::reverse(TC.definedFunctions)) {
TypeChecker::computeCaptures(FD);
}
// SWIFT_ENABLE_TENSORFLOW
// Check @compilerEvaluable function body correctness for all the functions
// defined in this file. We do this here, rather than in
// AttributeChecker::visitCompilerEvaluableAttr() because we need the function
// bodies to be type checked.
for (AbstractFunctionDecl *AFD : TC.definedFunctions) {
TC.checkFunctionBodyCompilerEvaluable(AFD);
}
TC.definedFunctions.clear();
}
void swift::typeCheckExternalDefinitions(SourceFile &SF) {
assert(SF.ASTStage == SourceFile::TypeChecked);
auto &Ctx = SF.getASTContext();
typeCheckFunctionsAndExternalDecls(SF, createTypeChecker(Ctx));
}
void swift::performTypeChecking(SourceFile &SF, TopLevelContext &TLC,
OptionSet<TypeCheckingFlags> Options,
unsigned StartElem,
unsigned WarnLongFunctionBodies,
unsigned WarnLongExpressionTypeChecking,
unsigned ExpressionTimeoutThreshold,
unsigned SwitchCheckingInvocationThreshold) {
if (SF.ASTStage == SourceFile::TypeChecked)
return;
// Eagerly build the top-level scopes tree before type checking
// because type-checking expressions mutates the AST and that throws off the
// scope-based lookups. Only the top-level scopes because extensions have not
// been bound yet.
if (SF.getASTContext().LangOpts.EnableASTScopeLookup &&
SF.isSuitableForASTScopes())
SF.getScope()
.buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals();
auto &Ctx = SF.getASTContext();
BufferIndirectlyCausingDiagnosticRAII cpr(SF);
// Make sure we have a type checker.
TypeChecker &TC = createTypeChecker(Ctx);
// Make sure that name binding has been completed before doing any type
// checking.
performNameBinding(SF, StartElem);
// Could build scope maps here because the AST is stable now.
{
SharedTimer timer("Type checking and Semantic analysis");
TC.setWarnLongFunctionBodies(WarnLongFunctionBodies);
TC.setWarnLongExpressionTypeChecking(WarnLongExpressionTypeChecking);
if (ExpressionTimeoutThreshold != 0)
TC.setExpressionTimeoutThreshold(ExpressionTimeoutThreshold);
if (SwitchCheckingInvocationThreshold != 0)
TC.setSwitchCheckingInvocationThreshold(
SwitchCheckingInvocationThreshold);
if (Options.contains(TypeCheckingFlags::DebugTimeFunctionBodies))
TC.enableDebugTimeFunctionBodies();
if (Options.contains(TypeCheckingFlags::DebugTimeExpressions))
TC.enableDebugTimeExpressions();
if (Options.contains(TypeCheckingFlags::ForImmediateMode))
TC.setInImmediateMode(true);
if (Options.contains(TypeCheckingFlags::SkipNonInlinableFunctionBodies))
// Disable this optimization if we're compiling SwiftOnoneSupport, because
// we _definitely_ need to look inside every declaration to figure out
// what gets prespecialized.
if (!SF.getParentModule()->isOnoneSupportModule())
TC.setSkipNonInlinableBodies(true);
// Lookup the swift module. This ensures that we record all known
// protocols in the AST.
(void) TC.getStdlibModule(&SF);
if (!Ctx.LangOpts.DisableAvailabilityChecking) {
// Build the type refinement hierarchy for the primary
// file before type checking.
TC.buildTypeRefinementContextHierarchy(SF, StartElem);
}
// Resolve extensions. This has to occur first during type checking,
// because the extensions need to be wired into the AST for name lookup
// to work.
bindExtensions(SF);
// Look for bridging functions. This only matters when
// -enable-source-import is provided.
checkBridgedFunctions(TC.Context);
// Type check the top-level elements of the source file.
for (auto D : llvm::makeArrayRef(SF.Decls).slice(StartElem)) {
if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(D)) {
// Immediately perform global name-binding etc.
TC.typeCheckTopLevelCodeDecl(TLCD);
TC.contextualizeTopLevelCode(TLC, TLCD);
} else {
TC.typeCheckDecl(D);
}
}
// If we're in REPL mode, inject temporary result variables and other stuff
// that the REPL needs to synthesize.
if (SF.Kind == SourceFileKind::REPL && !Ctx.hadError())
TC.processREPLTopLevel(SF, TLC, StartElem);
typeCheckFunctionsAndExternalDecls(SF, TC);
}
// Checking that benefits from having the whole module available.
if (!(Options & TypeCheckingFlags::DelayWholeModuleChecking)) {
performWholeModuleTypeChecking(SF);
}
// Verify that we've checked types correctly.
SF.ASTStage = SourceFile::TypeChecked;
{
SharedTimer timer("AST verification");
// Verify the SourceFile.
verify(SF);
// Verify imported modules.
//
// Skip per-file verification in whole-module mode. Verifying imports
// between files could cause the importer to cache declarations without
// adding them to the ASTContext. This happens when the importer registers a
// declaration without a valid TypeChecker instance, as is the case during
// verification. A subsequent file may require that declaration to be fully
// imported (e.g. to synthesized a function body), but since it has already
// been cached, it will never be added to the ASTContext. The solution is to
// skip verification and avoid caching it.
#ifndef NDEBUG
if (!(Options & TypeCheckingFlags::DelayWholeModuleChecking) &&
SF.Kind != SourceFileKind::REPL &&
SF.Kind != SourceFileKind::SIL &&
!Ctx.LangOpts.DebuggerSupport) {
Ctx.verifyAllLoadedModules();
}
#endif
}
}
void swift::performWholeModuleTypeChecking(SourceFile &SF) {
auto &Ctx = SF.getASTContext();
FrontendStatsTracer tracer(Ctx.Stats, "perform-whole-module-type-checking");
diagnoseAttrsRequiringFoundation(SF);
diagnoseObjCMethodConflicts(SF);
diagnoseObjCUnsatisfiedOptReqConflicts(SF);
diagnoseUnintendedObjCMethodOverrides(SF);
// In whole-module mode, import verification is deferred until all files have
// been type checked. This avoids caching imported declarations when a valid
// type checker is not present. The same declaration may need to be fully
// imported by subsequent files.
//
// FIXME: some playgrounds tests (playground_lvalues.swift) fail with
// verification enabled.
#if 0
if (SF.Kind != SourceFileKind::REPL &&
SF.Kind != SourceFileKind::SIL &&
!Ctx.LangOpts.DebuggerSupport) {
Ctx.verifyAllLoadedModules();
}
#endif
}
void swift::checkInconsistentImplementationOnlyImports(ModuleDecl *MainModule) {
bool hasAnyImplementationOnlyImports =
llvm::any_of(MainModule->getFiles(), [](const FileUnit *F) -> bool {
auto *SF = dyn_cast<SourceFile>(F);
return SF && SF->hasImplementationOnlyImports();
});
if (!hasAnyImplementationOnlyImports)
return;
auto diagnose = [MainModule](const ImportDecl *normalImport,
const ImportDecl *implementationOnlyImport) {
auto &diags = MainModule->getDiags();
{
InFlightDiagnostic warning =
diags.diagnose(normalImport, diag::warn_implementation_only_conflict,
normalImport->getModule()->getName());
if (normalImport->getAttrs().isEmpty()) {
// Only try to add a fix-it if there's no other annotations on the
// import to avoid creating things like
// `@_implementationOnly @_exported import Foo`. The developer can
// resolve those manually.
warning.fixItInsert(normalImport->getStartLoc(),
"@_implementationOnly ");
}
}
diags.diagnose(implementationOnlyImport,
diag::implementation_only_conflict_here);
};
llvm::DenseMap<ModuleDecl *, std::vector<const ImportDecl *>> normalImports;
llvm::DenseMap<ModuleDecl *, const ImportDecl *> implementationOnlyImports;
for (const FileUnit *file : MainModule->getFiles()) {
auto *SF = dyn_cast<SourceFile>(file);
if (!SF)
continue;
for (auto *topLevelDecl : SF->Decls) {
auto *nextImport = dyn_cast<ImportDecl>(topLevelDecl);
if (!nextImport)
continue;
ModuleDecl *module = nextImport->getModule();
if (!module)
continue;
if (nextImport->getAttrs().hasAttribute<ImplementationOnlyAttr>()) {
// We saw an implementation-only import.
bool isNew =
implementationOnlyImports.insert({module, nextImport}).second;
if (!isNew)
continue;
auto seenNormalImportPosition = normalImports.find(module);
if (seenNormalImportPosition != normalImports.end()) {
for (auto *seenNormalImport : seenNormalImportPosition->getSecond())
diagnose(seenNormalImport, nextImport);
// We're done with these; keep the map small if possible.
normalImports.erase(seenNormalImportPosition);
}
continue;
}
// We saw a non-implementation-only import. Is that in conflict with what
// we've seen?
if (auto *seenImplementationOnlyImport =
implementationOnlyImports.lookup(module)) {
diagnose(nextImport, seenImplementationOnlyImport);
continue;
}
// Otherwise, record it for later.
normalImports[module].push_back(nextImport);
}
}
}
bool swift::performTypeLocChecking(ASTContext &Ctx, TypeLoc &T,
DeclContext *DC,
bool ProduceDiagnostics) {
return performTypeLocChecking(
Ctx, T,
/*isSILMode=*/false,
/*isSILType=*/false,
/*GenericEnv=*/DC->getGenericEnvironmentOfContext(),
DC, ProduceDiagnostics);
}
bool swift::performTypeLocChecking(ASTContext &Ctx, TypeLoc &T,
bool isSILMode,
bool isSILType,
GenericEnvironment *GenericEnv,
DeclContext *DC,
bool ProduceDiagnostics) {
TypeResolutionOptions options = None;
// Fine to have unbound generic types.
options |= TypeResolutionFlags::AllowUnboundGenerics;
if (isSILMode) {
options |= TypeResolutionFlags::SILMode;
}
if (isSILType)
options |= TypeResolutionFlags::SILType;
auto resolution = TypeResolution::forContextual(DC, GenericEnv);
Optional<DiagnosticSuppression> suppression;
if (!ProduceDiagnostics)
suppression.emplace(Ctx.Diags);
TypeChecker &TC = createTypeChecker(Ctx);
return TypeChecker::validateType(TC.Context, T, resolution, options);
}
/// Expose TypeChecker's handling of GenericParamList to SIL parsing.
GenericEnvironment *
swift::handleSILGenericParams(ASTContext &Ctx, GenericParamList *genericParams,
DeclContext *DC) {
return createTypeChecker(Ctx).handleSILGenericParams(genericParams, DC);
}
void swift::typeCheckPatternBinding(PatternBindingDecl *PBD,
unsigned bindingIndex) {
assert(!PBD->isInitializerChecked(bindingIndex) &&
PBD->getInit(bindingIndex));
auto &Ctx = PBD->getASTContext();
DiagnosticSuppression suppression(Ctx.Diags);
TypeChecker &TC = createTypeChecker(Ctx);
TC.typeCheckPatternBinding(PBD, bindingIndex);
}
static Optional<Type> getTypeOfCompletionContextExpr(
TypeChecker &TC,
DeclContext *DC,
CompletionTypeCheckKind kind,
Expr *&parsedExpr,
ConcreteDeclRef &referencedDecl) {
if (TC.preCheckExpression(parsedExpr, DC))
return None;
switch (kind) {
case CompletionTypeCheckKind::Normal:
// Handle below.
break;
case CompletionTypeCheckKind::KeyPath:
referencedDecl = nullptr;
if (auto keyPath = dyn_cast<KeyPathExpr>(parsedExpr))
return TC.checkObjCKeyPathExpr(DC, keyPath, /*requireResultType=*/true);
return None;
}
Type originalType = parsedExpr->getType();
if (auto T = TC.getTypeOfExpressionWithoutApplying(parsedExpr, DC,
referencedDecl, FreeTypeVariableBinding::UnresolvedType))
return T;
// Try to recover if we've made any progress.
if (parsedExpr &&
!isa<ErrorExpr>(parsedExpr) &&
parsedExpr->getType() &&
!parsedExpr->getType()->hasError() &&
(originalType.isNull() ||
!parsedExpr->getType()->isEqual(originalType))) {
return parsedExpr->getType();
}
return None;
}
/// Return the type of an expression parsed during code completion, or
/// a null \c Type on error.
Optional<Type> swift::getTypeOfCompletionContextExpr(
ASTContext &Ctx,
DeclContext *DC,
CompletionTypeCheckKind kind,
Expr *&parsedExpr,
ConcreteDeclRef &referencedDecl) {
DiagnosticSuppression suppression(Ctx.Diags);
TypeChecker &TC = createTypeChecker(Ctx);
// Try to solve for the actual type of the expression.
return ::getTypeOfCompletionContextExpr(TC, DC, kind, parsedExpr,
referencedDecl);
}
/// Return the type of operator function for specified LHS, or a null
/// \c Type on error.
FunctionType *
swift::getTypeOfCompletionOperator(DeclContext *DC, Expr *LHS,
Identifier opName, DeclRefKind refKind,
ConcreteDeclRef &referencedDecl) {
auto &ctx = DC->getASTContext();
DiagnosticSuppression suppression(ctx.Diags);
TypeChecker &TC = createTypeChecker(ctx);
return TC.getTypeOfCompletionOperator(DC, LHS, opName, refKind,
referencedDecl);
}
bool swift::typeCheckExpression(DeclContext *DC, Expr *&parsedExpr) {
auto &ctx = DC->getASTContext();
DiagnosticSuppression suppression(ctx.Diags);
TypeChecker &TC = createTypeChecker(ctx);
auto resultTy = TC.typeCheckExpression(parsedExpr, DC, TypeLoc(),
ContextualTypePurpose::CTP_Unused);
return !resultTy;
}
bool swift::typeCheckAbstractFunctionBodyUntil(AbstractFunctionDecl *AFD,
SourceLoc EndTypeCheckLoc) {
auto &Ctx = AFD->getASTContext();
DiagnosticSuppression suppression(Ctx.Diags);
TypeChecker &TC = createTypeChecker(Ctx);
return !TC.typeCheckAbstractFunctionBodyUntil(AFD, EndTypeCheckLoc);
}
bool swift::typeCheckTopLevelCodeDecl(TopLevelCodeDecl *TLCD) {
auto &Ctx = static_cast<Decl *>(TLCD)->getASTContext();
DiagnosticSuppression suppression(Ctx.Diags);
TypeChecker &TC = createTypeChecker(Ctx);
TC.typeCheckTopLevelCodeDecl(TLCD);
return true;
}
TypeChecker &swift::createTypeChecker(ASTContext &Ctx) {
return TypeChecker::createForContext(Ctx);
}
// checkForForbiddenPrefix is for testing purposes.
void TypeChecker::checkForForbiddenPrefix(const Decl *D) {
if (!hasEnabledForbiddenTypecheckPrefix())
return;
if (auto VD = dyn_cast<ValueDecl>(D)) {
if (!VD->getBaseName().isSpecial())
checkForForbiddenPrefix(VD->getBaseName().getIdentifier().str());
}
}
void TypeChecker::checkForForbiddenPrefix(const UnresolvedDeclRefExpr *E) {
if (!hasEnabledForbiddenTypecheckPrefix())
return;
if (!E->getName().isSpecial())
checkForForbiddenPrefix(E->getName().getBaseIdentifier());
}
void TypeChecker::checkForForbiddenPrefix(Identifier Ident) {
if (!hasEnabledForbiddenTypecheckPrefix())
return;
checkForForbiddenPrefix(Ident.empty() ? StringRef() : Ident.str());
}
void TypeChecker::checkForForbiddenPrefix(StringRef Name) {
if (!hasEnabledForbiddenTypecheckPrefix())
return;
if (Name.empty())
return;
if (Name.startswith(Context.LangOpts.DebugForbidTypecheckPrefix)) {
std::string Msg = "forbidden typecheck occurred: ";
Msg += Name;
llvm::report_fatal_error(Msg);
}
}
DeclTypeCheckingSemantics
TypeChecker::getDeclTypeCheckingSemantics(ValueDecl *decl) {
// Check for a @_semantics attribute.
if (auto semantics = decl->getAttrs().getAttribute<SemanticsAttr>()) {
if (semantics->Value.equals("typechecker.type(of:)"))
return DeclTypeCheckingSemantics::TypeOf;
if (semantics->Value.equals("typechecker.withoutActuallyEscaping(_:do:)"))
return DeclTypeCheckingSemantics::WithoutActuallyEscaping;
if (semantics->Value.equals("typechecker._openExistential(_:do:)"))
return DeclTypeCheckingSemantics::OpenExistential;
}
return DeclTypeCheckingSemantics::Normal;
}