blob: e681c7ac5ba0a1c157ab48dbbb26c6ccd6121389 [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 "MiscDiagnostics.h"
#include "GenericTypeResolver.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/ASTVisitor.h"
#include "swift/AST/Attr.h"
#include "swift/AST/Identifier.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/Basic/STLExtras.h"
#include "swift/Basic/Timer.h"
#include "swift/ClangImporter/ClangImporter.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(ASTContext &Ctx, DiagnosticEngine &Diags)
: Context(Ctx), Diags(Diags)
{
auto clangImporter =
static_cast<ClangImporter *>(Context.getClangModuleLoader());
clangImporter->setTypeResolver(*this);
Context.setLazyResolver(this);
}
TypeChecker::~TypeChecker() {
auto clangImporter =
static_cast<ClangImporter *>(Context.getClangModuleLoader());
clangImporter->clearTypeResolver();
Context.setLazyResolver(nullptr);
}
void TypeChecker::handleExternalDecl(Decl *decl) {
if (auto SD = dyn_cast<StructDecl>(decl)) {
addImplicitConstructors(SD);
addImplicitStructConformances(SD);
}
if (auto CD = dyn_cast<ClassDecl>(decl)) {
addImplicitDestructor(CD);
}
if (auto ED = dyn_cast<EnumDecl>(decl)) {
addImplicitEnumConformances(ED);
}
}
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->hasInterfaceType()) {
validateDecl(protocol);
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, Context.Id_init,
{ Context.getIdentifier("colorLiteralRed"),
Context.getIdentifier("green"),
Context.getIdentifier("blue"),
Context.getIdentifier("alpha") });
}
case ObjectLiteralExpr::imageLiteral: {
return DeclName(Context, Context.Id_init,
{ Context.getIdentifier("imageLiteralResourceName") });
}
case ObjectLiteralExpr::fileLiteral: {
return DeclName(Context, Context.Id_init,
{ 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) {
Type argType = ctor->getArgumentInterfaceType();
auto argTuple = argType->getAs<TupleType>();
if (!argTuple) return argType;
auto replace = [&](StringRef replacement) -> Type {
SmallVector<TupleTypeElt, 4> elements;
elements.append(argTuple->getElements().begin(),
argTuple->getElements().end());
elements[0] = TupleTypeElt(elements[0].getType(),
Context.getIdentifier(replacement));
return TupleType::get(elements, Context);
};
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 (StdlibModule)
return StdlibModule;
if (!StdlibModule)
StdlibModule = Context.getStdlibModule();
if (!StdlibModule)
StdlibModule = dc->getParentModule();
assert(StdlibModule && "no main module found");
Context.recordKnownProtocols(StdlibModule);
return StdlibModule;
}
Type TypeChecker::lookupBoolType(const DeclContext *dc) {
if (!boolType) {
boolType = ([&] {
SmallVector<ValueDecl *, 2> results;
getStdlibModule(dc)->lookupValue({}, Context.getIdentifier("Bool"),
NLKind::QualifiedLookup, results);
if (results.size() != 1) {
diagnose(SourceLoc(), diag::broken_bool);
return Type();
}
auto tyDecl = dyn_cast<NominalTypeDecl>(results.front());
if (!tyDecl) {
diagnose(SourceLoc(), diag::broken_bool);
return Type();
}
return tyDecl->getDeclaredType();
})();
}
return *boolType;
}
namespace swift {
/// Clone the given generic parameters in the given list. We don't need any
/// of the requirements, because they will be inferred.
GenericParamList *cloneGenericParams(ASTContext &ctx,
DeclContext *dc,
GenericParamList *fromParams) {
// Clone generic parameters.
SmallVector<GenericTypeParamDecl *, 2> toGenericParams;
for (auto fromGP : *fromParams) {
// Create the new generic parameter.
auto toGP = new (ctx) GenericTypeParamDecl(dc, fromGP->getName(),
SourceLoc(),
fromGP->getDepth(),
fromGP->getIndex());
toGP->setImplicit(true);
// Record new generic parameter.
toGenericParams.push_back(toGP);
}
auto toParams = GenericParamList::create(ctx, SourceLoc(), toGenericParams,
SourceLoc());
auto outerParams = fromParams->getOuterParameters();
if (outerParams != nullptr)
outerParams = cloneGenericParams(ctx, dc, outerParams);
toParams->setOuterParameters(outerParams);
return toParams;
}
} // namespace swift
// FIXME: total hack
GenericParamList *createProtocolGenericParams(ASTContext &ctx,
ProtocolDecl *proto,
DeclContext *dc);
static void bindExtensionDecl(ExtensionDecl *ED, TypeChecker &TC) {
if (ED->getExtendedType())
return;
// If we didn't parse a type, fill in an error type and bail out.
if (!ED->getExtendedTypeLoc().getTypeRepr()) {
ED->setInvalid();
ED->getExtendedTypeLoc().setInvalidType(TC.Context);
return;
}
auto dc = ED->getDeclContext();
// Validate the representation.
// FIXME: Perform some kind of "shallow" validation here?
TypeResolutionOptions options;
options |= TR_AllowUnboundGenerics;
options |= TR_ExtensionBinding;
if (TC.validateType(ED->getExtendedTypeLoc(), dc, options)) {
ED->setInvalid();
return;
}
// Dig out the extended type.
auto extendedType = ED->getExtendedType();
// Hack to allow extending a generic typealias.
if (auto *unboundGeneric = extendedType->getAs<UnboundGenericType>()) {
if (auto *aliasDecl = dyn_cast<TypeAliasDecl>(unboundGeneric->getDecl())) {
auto extendedNominal = aliasDecl->getDeclaredInterfaceType()->getAnyNominal();
if (extendedNominal) {
extendedType = extendedNominal->getDeclaredType();
ED->getExtendedTypeLoc().setType(extendedType);
}
}
}
// Handle easy cases.
// Cannot extend a metatype.
if (extendedType->is<AnyMetatypeType>()) {
TC.diagnose(ED->getLoc(), diag::extension_metatype, extendedType)
.highlight(ED->getExtendedTypeLoc().getSourceRange());
ED->setInvalid();
ED->getExtendedTypeLoc().setInvalidType(TC.Context);
return;
}
// Cannot extend a bound generic type.
if (extendedType->isSpecialized()) {
TC.diagnose(ED->getLoc(), diag::extension_specialization,
extendedType->getAnyNominal()->getName())
.highlight(ED->getExtendedTypeLoc().getSourceRange());
ED->setInvalid();
ED->getExtendedTypeLoc().setInvalidType(TC.Context);
return;
}
// Dig out the nominal type being extended.
NominalTypeDecl *extendedNominal = extendedType->getAnyNominal();
if (!extendedNominal) {
TC.diagnose(ED->getLoc(), diag::non_nominal_extension, extendedType)
.highlight(ED->getExtendedTypeLoc().getSourceRange());
ED->setInvalid();
ED->getExtendedTypeLoc().setInvalidType(TC.Context);
return;
}
assert(extendedNominal && "Should have the nominal type being extended");
// If the extended type is generic or is a protocol. Clone or create
// the generic parameters.
if (extendedNominal->isGenericContext()) {
if (auto proto = dyn_cast<ProtocolDecl>(extendedNominal)) {
// For a protocol extension, build the generic parameter list.
ED->setGenericParams(proto->createGenericParams(ED));
} else {
// Clone the existing generic parameter list.
ED->setGenericParams(
cloneGenericParams(TC.Context, ED,
extendedNominal->getGenericParamsOfContext()));
}
}
// If we have a trailing where clause, deal with it now.
// For now, trailing where clauses are only permitted on protocol extensions.
if (auto trailingWhereClause = ED->getTrailingWhereClause()) {
if (!extendedNominal->isGenericContext()) {
// Only generic and protocol types are permitted to have
// trailing where clauses.
TC.diagnose(ED, diag::extension_nongeneric_trailing_where, extendedType)
.highlight(trailingWhereClause->getSourceRange());
ED->setTrailingWhereClause(nullptr);
} else {
// Merge the trailing where clause into the generic parameter list.
// FIXME: Long-term, we'd like clients to deal with the trailing where
// clause explicitly, but for now it's far more direct to represent
// the trailing where clause as part of the requirements.
ED->getGenericParams()->addTrailingWhereClause(
TC.Context,
trailingWhereClause->getWhereLoc(),
trailingWhereClause->getRequirements());
}
}
extendedNominal->addExtension(ED);
}
void TypeChecker::bindExtension(ExtensionDecl *ext) {
::bindExtensionDecl(ext, *this);
}
static bool shouldValidateDeclForLayout(NominalTypeDecl *nominal, ValueDecl *VD) {
// For enums, we only need to validate enum elements to know
// the layout.
if (isa<EnumDecl>(nominal) &&
isa<EnumElementDecl>(VD))
return true;
// For structs, we only need to validate stored properties to
// know the layout.
if (isa<StructDecl>(nominal) &&
(isa<VarDecl>(VD) &&
!cast<VarDecl>(VD)->isStatic() &&
(cast<VarDecl>(VD)->hasStorage() ||
VD->getAttrs().hasAttribute<LazyAttr>())))
return true;
// For classes, we need to validate properties and functions,
// but skipping nested types is OK.
if (isa<ClassDecl>(nominal) &&
!isa<TypeDecl>(VD))
return true;
// For protocols, skip nested typealiases and nominal types.
if (isa<ProtocolDecl>(nominal) &&
!isa<GenericTypeDecl>(VD))
return true;
return false;
}
static void validateDeclForLayout(TypeChecker &TC, NominalTypeDecl *nominal) {
Optional<bool> lazyVarsAlreadyHaveImplementation;
for (auto *D : nominal->getMembers()) {
auto VD = dyn_cast<ValueDecl>(D);
if (!VD)
continue;
if (!shouldValidateDeclForLayout(nominal, VD))
continue;
TC.validateDecl(VD);
// The only thing left to do is synthesize storage for lazy variables.
// We only have to do that if it's a type from another file, though.
// In NDEBUG builds, bail out as soon as we can.
#ifdef NDEBUG
if (lazyVarsAlreadyHaveImplementation.hasValue() &&
lazyVarsAlreadyHaveImplementation.getValue())
continue;
#endif
auto *prop = dyn_cast<VarDecl>(D);
if (!prop)
continue;
if (prop->getAttrs().hasAttribute<LazyAttr>() && !prop->isStatic()
&& prop->getGetter()) {
bool hasImplementation = prop->getGetter()->hasBody();
if (lazyVarsAlreadyHaveImplementation.hasValue()) {
assert(lazyVarsAlreadyHaveImplementation.getValue() ==
hasImplementation &&
"only some lazy vars already have implementations");
} else {
lazyVarsAlreadyHaveImplementation = hasImplementation;
}
if (!hasImplementation)
TC.completeLazyVarImplementation(prop);
}
}
// FIXME: We need to add implicit initializers and dtors when a decl is
// touched, because it affects vtable layout. If you're not defining the
// class, you shouldn't have to know what the vtable layout is.
if (auto *CD = dyn_cast<ClassDecl>(nominal)) {
TC.addImplicitConstructors(CD);
TC.addImplicitDestructor(CD);
}
}
static void typeCheckFunctionsAndExternalDecls(TypeChecker &TC) {
unsigned currentFunctionIdx = 0;
unsigned currentExternalDef = TC.Context.LastCheckedExternalDefinition;
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 = TC.definedFunctions.size(); currentFunctionIdx != n;
++currentFunctionIdx) {
auto *AFD = TC.definedFunctions[currentFunctionIdx];
// HACK: don't type-check the same function body twice. This is
// supposed to be handled by just not enqueuing things twice,
// but that gets tricky with synthesized function bodies.
if (AFD->isBodyTypeChecked()) continue;
PrettyStackTraceDecl StackEntry("type-checking", AFD);
TC.typeCheckAbstractFunctionBody(AFD);
AFD->setBodyTypeCheckedIfPresent();
}
for (unsigned n = TC.Context.ExternalDefinitions.size();
currentExternalDef != n;
++currentExternalDef) {
auto decl = TC.Context.ExternalDefinitions[currentExternalDef];
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(decl)) {
// HACK: don't type-check the same function body twice. This is
// supposed to be handled by just not enqueuing things twice,
// but that gets tricky with synthesized function bodies.
if (AFD->isBodyTypeChecked()) continue;
PrettyStackTraceDecl StackEntry("type-checking", AFD);
TC.typeCheckAbstractFunctionBody(AFD);
continue;
}
if (isa<NominalTypeDecl>(decl)) {
TC.handleExternalDecl(decl);
continue;
}
if (isa<VarDecl>(decl))
continue;
llvm_unreachable("Unhandled external definition kind");
}
// Validate the contents of any referenced nominal types for SIL's purposes.
// Note: if we ever start putting extension members in vtables, we'll need
// to validate those members too.
// FIXME: If we're not planning to run SILGen, this is wasted effort.
while (!TC.ValidatedTypes.empty()) {
auto nominal = TC.ValidatedTypes.pop_back_val();
if (nominal->isInvalid() || TC.Context.hadError())
continue;
validateDeclForLayout(TC, nominal);
}
// Complete any conformances that we used.
for (unsigned i = 0; i != TC.UsedConformances.size(); ++i) {
auto conformance = TC.UsedConformances[i];
if (conformance->isIncomplete())
TC.checkConformance(conformance);
}
TC.UsedConformances.clear();
} while (currentFunctionIdx < TC.definedFunctions.size() ||
currentExternalDef < TC.Context.ExternalDefinitions.size() ||
!TC.ValidatedTypes.empty() ||
!TC.UsedConformances.empty());
// FIXME: Horrible hack. Store this somewhere more appropriate.
TC.Context.LastCheckedExternalDefinition = currentExternalDef;
// Compute captures for functions and closures we visited.
for (AnyFunctionRef closure : TC.ClosuresWithUncomputedCaptures) {
TC.computeCaptures(closure);
}
for (AbstractFunctionDecl *FD : reversed(TC.definedFunctions)) {
TC.computeCaptures(FD);
}
// Check error-handling correctness for all the functions defined in
// this file. This can depend on all of their interior function
// bodies having been type-checked.
for (AbstractFunctionDecl *FD : TC.definedFunctions) {
TC.checkFunctionErrorHandling(FD);
}
for (auto decl : TC.Context.ExternalDefinitions) {
if (auto fn = dyn_cast<AbstractFunctionDecl>(decl)) {
TC.checkFunctionErrorHandling(fn);
}
}
}
void swift::typeCheckExternalDefinitions(SourceFile &SF) {
assert(SF.ASTStage == SourceFile::TypeChecked);
auto &Ctx = SF.getASTContext();
TypeChecker TC(Ctx);
typeCheckFunctionsAndExternalDecls(TC);
}
void swift::performTypeChecking(SourceFile &SF, TopLevelContext &TLC,
OptionSet<TypeCheckingFlags> Options,
unsigned StartElem,
unsigned WarnLongFunctionBodies) {
if (SF.ASTStage == SourceFile::TypeChecked)
return;
auto &Ctx = SF.getASTContext();
// Make sure we have a type checker.
Optional<TypeChecker> MyTC;
if (!Ctx.getLazyResolver())
MyTC.emplace(Ctx);
// Make sure that name binding has been completed before doing any type
// checking.
{
SharedTimer timer("Name binding");
performNameBinding(SF, StartElem);
}
{
// NOTE: The type checker is scoped to be torn down before AST
// verification.
SharedTimer timer("Type checking / Semantic analysis");
if (MyTC) {
MyTC->setWarnLongFunctionBodies(WarnLongFunctionBodies);
if (Options.contains(TypeCheckingFlags::DebugTimeFunctionBodies))
MyTC->enableDebugTimeFunctionBodies();
if (Options.contains(TypeCheckingFlags::DebugTimeExpressions))
MyTC->enableDebugTimeExpressions();
if (Options.contains(TypeCheckingFlags::ForImmediateMode))
MyTC->setInImmediateMode(true);
// Lookup the swift module. This ensures that we record all known
// protocols in the AST.
(void) MyTC->getStdlibModule(&SF);
if (!Ctx.LangOpts.DisableAvailabilityChecking) {
// Build the type refinement hierarchy for the primary
// file before type checking.
MyTC->buildTypeRefinementContextHierarchy(SF, StartElem);
}
}
TypeChecker &TC =
MyTC ? *MyTC : *static_cast<TypeChecker *>(Ctx.getLazyResolver());
// 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.
// FIXME: We can have interesting ordering dependencies among the various
// extensions, so we'll need to be smarter here.
// FIXME: The current source file needs to be handled specially, because of
// private extensions.
SF.forAllVisibleModules([&](ModuleDecl::ImportedModule import) {
// 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))
bindExtensionDecl(ED, TC);
}
}
});
// FIXME: Check for cycles in class inheritance here?
// Type check the top-level elements of the source file.
for (auto D : llvm::makeArrayRef(SF.Decls).slice(StartElem)) {
if (isa<TopLevelCodeDecl>(D))
continue;
TC.typeCheckDecl(D, /*isFirstPass*/true);
}
// At this point, we can perform general name lookup into any type.
// We don't know the types of all the global declarations in the first
// pass, which means we can't completely analyze everything. Perform the
// second pass now.
bool hasTopLevelCode = false;
for (auto D : llvm::makeArrayRef(SF.Decls).slice(StartElem)) {
if (TopLevelCodeDecl *TLCD = dyn_cast<TopLevelCodeDecl>(D)) {
hasTopLevelCode = true;
// Immediately perform global name-binding etc.
TC.typeCheckTopLevelCodeDecl(TLCD);
} else {
TC.typeCheckDecl(D, /*isFirstPass*/false);
}
}
if (hasTopLevelCode) {
TC.contextualizeTopLevelCode(TLC,
llvm::makeArrayRef(SF.Decls).slice(StartElem));
}
// 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(TC);
}
MyTC.reset();
// 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.
#ifndef NDEBUG
if (SF.Kind != SourceFileKind::REPL &&
SF.Kind != SourceFileKind::SIL &&
!Ctx.LangOpts.DebuggerSupport) {
Ctx.verifyAllLoadedModules();
}
#endif
}
}
void swift::finishTypeChecking(SourceFile &SF) {
auto &Ctx = SF.getASTContext();
TypeChecker TC(Ctx);
for (auto D : SF.Decls)
if (auto PD = dyn_cast<ProtocolDecl>(D))
TC.inferDefaultWitnesses(PD);
}
void swift::performWholeModuleTypeChecking(SourceFile &SF) {
auto &Ctx = SF.getASTContext();
Ctx.diagnoseAttrsRequiringFoundation(SF);
Ctx.diagnoseObjCMethodConflicts(SF);
Ctx.diagnoseObjCUnsatisfiedOptReqConflicts(SF);
Ctx.diagnoseUnintendedObjCMethodOverrides(SF);
}
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;
// Fine to have unbound generic types.
options |= TR_AllowUnboundGenerics;
if (isSILMode)
options |= TR_SILMode;
if (isSILType)
options |= TR_SILType;
GenericTypeToArchetypeResolver contextResolver(GenericEnv);
if (ProduceDiagnostics) {
return TypeChecker(Ctx).validateType(T, DC, options, &contextResolver);
} else {
// Set up a diagnostics engine that swallows diagnostics.
DiagnosticEngine Diags(Ctx.SourceMgr);
return TypeChecker(Ctx, Diags).validateType(T, DC, options,
&contextResolver);
}
}
/// Expose TypeChecker's handling of GenericParamList to SIL parsing.
GenericEnvironment *
swift::handleSILGenericParams(ASTContext &Ctx, GenericParamList *genericParams,
DeclContext *DC) {
return TypeChecker(Ctx).handleSILGenericParams(genericParams, DC);
}
bool swift::typeCheckCompletionDecl(Decl *D) {
auto &Ctx = D->getASTContext();
// Set up a diagnostics engine that swallows diagnostics.
DiagnosticEngine Diags(Ctx.SourceMgr);
TypeChecker TC(Ctx, Diags);
if (auto ext = dyn_cast<ExtensionDecl>(D))
TC.validateExtension(ext);
else
TC.typeCheckDecl(D, true);
return true;
}
static Optional<Type> getTypeOfCompletionContextExpr(
TypeChecker &TC,
DeclContext *DC,
CompletionTypeCheckKind kind,
Expr *&parsedExpr,
ConcreteDeclRef &referencedDecl) {
switch (kind) {
case CompletionTypeCheckKind::Normal:
// Handle below.
break;
case CompletionTypeCheckKind::ObjCKeyPath:
referencedDecl = nullptr;
if (auto keyPath = dyn_cast<ObjCKeyPathExpr>(parsedExpr))
return TC.checkObjCKeyPathExpr(DC, keyPath, /*requireResultType=*/true);
return None;
}
Type originalType = parsedExpr->getType();
if (auto T = TC.getTypeOfExpressionWithoutApplying(parsedExpr, DC,
referencedDecl, FreeTypeVariableBinding::GenericParameters))
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;
}
/// \brief 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) {
if (Ctx.getLazyResolver()) {
TypeChecker *TC = static_cast<TypeChecker *>(Ctx.getLazyResolver());
return ::getTypeOfCompletionContextExpr(*TC, DC, kind, parsedExpr,
referencedDecl);
} else {
// Set up a diagnostics engine that swallows diagnostics.
DiagnosticEngine diags(Ctx.SourceMgr);
TypeChecker TC(Ctx, diags);
// Try to solve for the actual type of the expression.
return ::getTypeOfCompletionContextExpr(TC, DC, kind, parsedExpr,
referencedDecl);
}
}
bool swift::typeCheckCompletionSequence(DeclContext *DC, Expr *&parsedExpr) {
auto &ctx = DC->getASTContext();
if (ctx.getLazyResolver()) {
TypeChecker *TC = static_cast<TypeChecker *>(ctx.getLazyResolver());
return TC->typeCheckCompletionSequence(parsedExpr, DC);
} else {
// Set up a diagnostics engine that swallows diagnostics.
DiagnosticEngine diags(ctx.SourceMgr);
TypeChecker TC(ctx, diags);
return TC.typeCheckCompletionSequence(parsedExpr, DC);
}
}
bool swift::typeCheckExpression(DeclContext *DC, Expr *&parsedExpr) {
auto &ctx = DC->getASTContext();
if (ctx.getLazyResolver()) {
TypeChecker *TC = static_cast<TypeChecker *>(ctx.getLazyResolver());
return TC->typeCheckExpression(parsedExpr, DC);
} else {
// Set up a diagnostics engine that swallows diagnostics.
DiagnosticEngine diags(ctx.SourceMgr);
TypeChecker TC(ctx, diags);
return TC.typeCheckExpression(parsedExpr, DC);
}
}
bool swift::typeCheckAbstractFunctionBodyUntil(AbstractFunctionDecl *AFD,
SourceLoc EndTypeCheckLoc) {
auto &Ctx = AFD->getASTContext();
// Set up a diagnostics engine that swallows diagnostics.
DiagnosticEngine Diags(Ctx.SourceMgr);
TypeChecker TC(Ctx, Diags);
return !TC.typeCheckAbstractFunctionBodyUntil(AFD, EndTypeCheckLoc);
}
bool swift::typeCheckTopLevelCodeDecl(TopLevelCodeDecl *TLCD) {
auto &Ctx = static_cast<Decl *>(TLCD)->getASTContext();
// Set up a diagnostics engine that swallows diagnostics.
DiagnosticEngine Diags(Ctx.SourceMgr);
TypeChecker TC(Ctx, Diags);
TC.typeCheckTopLevelCodeDecl(TLCD);
return true;
}
static void deleteTypeCheckerAndDiags(LazyResolver *resolver) {
DiagnosticEngine &diags = static_cast<TypeChecker*>(resolver)->Diags;
delete resolver;
delete &diags;
}
OwnedResolver swift::createLazyResolver(ASTContext &Ctx) {
auto diags = new DiagnosticEngine(Ctx.SourceMgr);
return OwnedResolver(new TypeChecker(Ctx, *diags),
&deleteTypeCheckerAndDiags);
}
void TypeChecker::diagnoseAmbiguousMemberType(Type baseTy,
SourceRange baseRange,
Identifier name,
SourceLoc nameLoc,
LookupTypeResult &lookup) {
if (auto moduleTy = baseTy->getAs<ModuleType>()) {
diagnose(nameLoc, diag::ambiguous_module_type, name,
moduleTy->getModule()->getName())
.highlight(baseRange);
} else {
diagnose(nameLoc, diag::ambiguous_member_type, name, baseTy)
.highlight(baseRange);
}
for (const auto &member : lookup) {
diagnose(member.first, diag::found_candidate_type,
member.second);
}
}
// checkForForbiddenPrefix is for testing purposes.
void TypeChecker::checkForForbiddenPrefix(const Decl *D) {
if (!hasEnabledForbiddenTypecheckPrefix())
return;
if (auto VD = dyn_cast<ValueDecl>(D)) {
checkForForbiddenPrefix(VD->getNameStr());
}
}
void TypeChecker::checkForForbiddenPrefix(const UnresolvedDeclRefExpr *E) {
if (!hasEnabledForbiddenTypecheckPrefix())
return;
checkForForbiddenPrefix(E->getName().getBaseName());
}
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;
}
return DeclTypeCheckingSemantics::Normal;
}