blob: d8806c5b8e4e21a54fe96e49a10a90fcbaa88ebb [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/AST/TypeCheckRequests.h"
#include "swift/Basic/Statistic.h"
#include "swift/Basic/STLExtras.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;
ProtocolDecl *TypeChecker::getProtocol(ASTContext &Context, SourceLoc loc,
KnownProtocolKind kind) {
auto protocol = Context.getProtocol(kind);
if (!protocol && loc.isValid()) {
Context.Diags.diagnose(loc, diag::missing_protocol,
Context.getIdentifier(getProtocolName(kind)));
}
if (protocol && protocol->isInvalid()) {
return nullptr;
}
return protocol;
}
ProtocolDecl *TypeChecker::getLiteralProtocol(ASTContext &Context, Expr *expr) {
if (isa<ArrayExpr>(expr))
return TypeChecker::getProtocol(
Context, expr->getLoc(), KnownProtocolKind::ExpressibleByArrayLiteral);
if (isa<DictionaryExpr>(expr))
return TypeChecker::getProtocol(
Context, expr->getLoc(),
KnownProtocolKind::ExpressibleByDictionaryLiteral);
if (!isa<LiteralExpr>(expr))
return nullptr;
if (isa<NilLiteralExpr>(expr))
return TypeChecker::getProtocol(Context, expr->getLoc(),
KnownProtocolKind::ExpressibleByNilLiteral);
if (isa<IntegerLiteralExpr>(expr))
return TypeChecker::getProtocol(
Context, expr->getLoc(),
KnownProtocolKind::ExpressibleByIntegerLiteral);
if (isa<FloatLiteralExpr>(expr))
return TypeChecker::getProtocol(
Context, expr->getLoc(), KnownProtocolKind::ExpressibleByFloatLiteral);
if (isa<BooleanLiteralExpr>(expr))
return TypeChecker::getProtocol(
Context, expr->getLoc(),
KnownProtocolKind::ExpressibleByBooleanLiteral);
if (const auto *SLE = dyn_cast<StringLiteralExpr>(expr)) {
if (SLE->isSingleUnicodeScalar())
return TypeChecker::getProtocol(
Context, expr->getLoc(),
KnownProtocolKind::ExpressibleByUnicodeScalarLiteral);
if (SLE->isSingleExtendedGraphemeCluster())
return getProtocol(
Context, expr->getLoc(),
KnownProtocolKind::ExpressibleByExtendedGraphemeClusterLiteral);
return TypeChecker::getProtocol(
Context, expr->getLoc(), KnownProtocolKind::ExpressibleByStringLiteral);
}
if (isa<InterpolatedStringLiteralExpr>(expr))
return TypeChecker::getProtocol(
Context, expr->getLoc(),
KnownProtocolKind::ExpressibleByStringInterpolation);
if (auto E = dyn_cast<MagicIdentifierLiteralExpr>(expr)) {
switch (E->getKind()) {
#define MAGIC_STRING_IDENTIFIER(NAME, STRING, SYNTAX_KIND) \
case MagicIdentifierLiteralExpr::NAME: \
return TypeChecker::getProtocol( \
Context, expr->getLoc(), \
KnownProtocolKind::ExpressibleByStringLiteral);
#define MAGIC_INT_IDENTIFIER(NAME, STRING, SYNTAX_KIND) \
case MagicIdentifierLiteralExpr::NAME: \
return TypeChecker::getProtocol( \
Context, expr->getLoc(), \
KnownProtocolKind::ExpressibleByIntegerLiteral);
#define MAGIC_POINTER_IDENTIFIER(NAME, STRING, SYNTAX_KIND) \
case MagicIdentifierLiteralExpr::NAME: \
return nullptr;
#include "swift/AST/MagicIdentifierKinds.def"
}
}
if (auto E = dyn_cast<ObjectLiteralExpr>(expr)) {
switch (E->getLiteralKind()) {
#define POUND_OBJECT_LITERAL(Name, Desc, Protocol) \
case ObjectLiteralExpr::Name: \
return TypeChecker::getProtocol(Context, expr->getLoc(), \
KnownProtocolKind::Protocol);
#include "swift/Syntax/TokenKinds.def"
}
}
return nullptr;
}
DeclName TypeChecker::getObjectLiteralConstructorName(ASTContext &Context,
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");
}
ModuleDecl *TypeChecker::getStdlibModule(const DeclContext *dc) {
if (auto *stdlib = dc->getASTContext().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);
}
void swift::bindExtensions(ModuleDecl &mod) {
// 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;
for (auto file : mod.getFiles()) {
auto *SF = dyn_cast<SourceFile>(file);
if (!SF)
continue;
auto visitTopLevelDecl = [&](Decl *D) {
if (auto ED = dyn_cast<ExtensionDecl>(D))
if (!tryBindExtension(ED))
worklist.push_back(ED);;
};
for (auto *D : SF->getTopLevelDecls())
visitTopLevelDecl(D);
for (auto *D : SF->getHoistedDecls())
visitTopLevelDecl(D);
}
// 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 typeCheckDelayedFunctions(SourceFile &SF) {
unsigned currentFunctionIdx = 0;
unsigned currentSynthesizedDecl = SF.LastCheckedSynthesizedDecl;
do {
// 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 = SF.DelayedFunctions.size(); currentFunctionIdx != n;
++currentFunctionIdx) {
auto *AFD = SF.DelayedFunctions[currentFunctionIdx];
assert(!AFD->getDeclContext()->isLocalContext());
(void)AFD->getTypecheckedBody();
}
// Type check synthesized functions and their bodies.
for (unsigned n = SF.SynthesizedDecls.size();
currentSynthesizedDecl != n;
++currentSynthesizedDecl) {
auto decl = SF.SynthesizedDecls[currentSynthesizedDecl];
TypeChecker::typeCheckDecl(decl);
}
} while (currentFunctionIdx < SF.DelayedFunctions.size() ||
currentSynthesizedDecl < SF.SynthesizedDecls.size());
SF.DelayedFunctions.clear();
}
void swift::performTypeChecking(SourceFile &SF) {
return (void)evaluateOrDefault(SF.getASTContext().evaluator,
TypeCheckSourceFileRequest{&SF}, {});
}
evaluator::SideEffect
TypeCheckSourceFileRequest::evaluate(Evaluator &eval, SourceFile *SF) const {
assert(SF && "Source file cannot be null!");
assert(SF->ASTStage != SourceFile::TypeChecked &&
"Should not be re-typechecking this file!");
// 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.
auto &Ctx = SF->getASTContext();
SF->getScope()
.buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals();
BufferIndirectlyCausingDiagnosticRAII cpr(*SF);
// Could build scope maps here because the AST is stable now.
{
FrontendStatsTracer tracer(Ctx.Stats,
"Type checking and Semantic analysis");
if (!Ctx.LangOpts.DisableAvailabilityChecking) {
// Build the type refinement hierarchy for the primary
// file before type checking.
TypeChecker::buildTypeRefinementContextHierarchy(*SF);
}
// Type check the top-level elements of the source file.
for (auto D : SF->getTopLevelDecls()) {
if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(D)) {
TypeChecker::typeCheckTopLevelCodeDecl(TLCD);
TypeChecker::contextualizeTopLevelCode(TLCD);
} else {
TypeChecker::typeCheckDecl(D);
}
}
typeCheckDelayedFunctions(*SF);
}
// Check to see if there's any inconsistent @_implementationOnly imports.
evaluateOrDefault(
Ctx.evaluator,
CheckInconsistentImplementationOnlyImportsRequest{SF->getParentModule()},
{});
// Perform various AST transforms we've been asked to perform.
if (!Ctx.hadError() && Ctx.LangOpts.DebuggerTestingTransform)
performDebuggerTestingTransform(*SF);
if (!Ctx.hadError() && Ctx.LangOpts.PCMacro)
performPCMacro(*SF);
// Playground transform knows to look out for PCMacro's changes and not
// to playground log them.
if (!Ctx.hadError() && Ctx.LangOpts.PlaygroundTransform)
performPlaygroundTransform(*SF, Ctx.LangOpts.PlaygroundHighPerformance);
return std::make_tuple<>();
}
void swift::performWholeModuleTypeChecking(SourceFile &SF) {
auto &Ctx = SF.getASTContext();
FrontendStatsTracer tracer(Ctx.Stats,
"perform-whole-module-type-checking");
switch (SF.Kind) {
case SourceFileKind::Library:
case SourceFileKind::Main:
diagnoseObjCMethodConflicts(SF);
diagnoseObjCUnsatisfiedOptReqConflicts(SF);
diagnoseUnintendedObjCMethodOverrides(SF);
return;
case SourceFileKind::SIL:
case SourceFileKind::Interface:
// SIL modules and .swiftinterface files don't benefit from whole-module
// ObjC checking - skip it.
return;
}
}
bool swift::isAdditiveArithmeticConformanceDerivationEnabled(SourceFile &SF) {
auto &ctx = SF.getASTContext();
// Return true if `AdditiveArithmetic` derived conformances are explicitly
// enabled.
if (ctx.LangOpts.EnableExperimentalAdditiveArithmeticDerivedConformances)
return true;
// Otherwise, return true iff differentiable programming is enabled.
// Differentiable programming depends on `AdditiveArithmetic` derived
// conformances.
return isDifferentiableProgrammingEnabled(SF);
}
Type swift::performTypeResolution(TypeRepr *TyR, ASTContext &Ctx,
bool isSILMode, bool isSILType,
GenericEnvironment *GenericEnv,
GenericParamList *GenericParams,
DeclContext *DC, bool ProduceDiagnostics) {
TypeResolutionOptions options = None;
if (isSILMode)
options |= TypeResolutionFlags::SILMode;
if (isSILType)
options |= TypeResolutionFlags::SILType;
const auto resolution =
TypeResolution::forContextual(DC, GenericEnv, options,
[](auto unboundTy) {
// FIXME: Don't let unbound generic types escape type resolution.
// For now, just return the unbound generic type.
return unboundTy;
});
Optional<DiagnosticSuppression> suppression;
if (!ProduceDiagnostics)
suppression.emplace(Ctx.Diags);
return resolution.resolveType(TyR, GenericParams);
}
namespace {
class BindGenericParamsWalker : public ASTWalker {
DeclContext *dc;
GenericParamList *params;
public:
BindGenericParamsWalker(DeclContext *dc,
GenericParamList *params)
: dc(dc), params(params) {}
bool walkToTypeReprPre(TypeRepr *T) override {
if (auto *ident = dyn_cast<IdentTypeRepr>(T)) {
auto firstComponent = ident->getComponentRange().front();
auto name = firstComponent->getNameRef().getBaseIdentifier();
if (auto *paramDecl = params->lookUpGenericParam(name))
firstComponent->setValue(paramDecl, dc);
}
return true;
}
};
};
/// Expose TypeChecker's handling of GenericParamList to SIL parsing.
GenericEnvironment *
swift::handleSILGenericParams(GenericParamList *genericParams,
DeclContext *DC) {
if (genericParams == nullptr)
return nullptr;
SmallVector<GenericParamList *, 2> nestedList;
for (auto *innerParams = genericParams;
innerParams != nullptr;
innerParams = innerParams->getOuterParameters()) {
nestedList.push_back(innerParams);
}
std::reverse(nestedList.begin(), nestedList.end());
BindGenericParamsWalker walker(DC, genericParams);
for (unsigned i = 0, e = nestedList.size(); i < e; ++i) {
auto genericParams = nestedList[i];
genericParams->setDepth(i);
genericParams->walk(walker);
}
auto sig =
TypeChecker::checkGenericSignature(nestedList.back(), DC,
/*parentSig=*/nullptr,
/*allowConcreteGenericParams=*/true);
return (sig ? sig->getGenericEnvironment() : nullptr);
}
void swift::typeCheckPatternBinding(PatternBindingDecl *PBD,
unsigned bindingIndex) {
assert(!PBD->isInitializerChecked(bindingIndex) &&
PBD->getInit(bindingIndex));
auto &Ctx = PBD->getASTContext();
DiagnosticSuppression suppression(Ctx.Diags);
(void)evaluateOrDefault(
Ctx.evaluator, PatternBindingEntryRequest{PBD, bindingIndex}, nullptr);
TypeChecker::typeCheckPatternBinding(PBD, bindingIndex);
}
bool swift::typeCheckASTNodeAtLoc(DeclContext *DC, SourceLoc TargetLoc) {
auto &Ctx = DC->getASTContext();
DiagnosticSuppression suppression(Ctx.Diags);
return !evaluateOrDefault(Ctx.evaluator,
TypeCheckASTNodeAtLocRequest{DC, TargetLoc},
true);
}
bool swift::typeCheckTopLevelCodeDecl(TopLevelCodeDecl *TLCD) {
auto &Ctx = static_cast<Decl *>(TLCD)->getASTContext();
DiagnosticSuppression suppression(Ctx.Diags);
TypeChecker::typeCheckTopLevelCodeDecl(TLCD);
return true;
}
void TypeChecker::checkForForbiddenPrefix(ASTContext &C, DeclBaseName Name) {
if (C.TypeCheckerOpts.DebugForbidTypecheckPrefix.empty())
return;
// Don't touch special names or empty names.
if (Name.isSpecial() || Name.empty())
return;
StringRef Str = Name.getIdentifier().str();
if (Str.startswith(C.TypeCheckerOpts.DebugForbidTypecheckPrefix)) {
std::string Msg = "forbidden typecheck occurred: ";
Msg += Str;
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;
}