blob: dc8e9cbe3a22a9e846fc0c162ab9900c476ec19b [file] [log] [blame]
//===--- IDETypeChecking.h - Type-check entry points ------------*- C++ -*-===//
// This source file is part of the 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 for license information
// See for the list of Swift project authors
/// \file
/// Provides extra type-checking entry points for use during code
/// completion, which happens *without* type-checking an entire file at once.
#include "swift/AST/Identifier.h"
#include "swift/Basic/SourceLoc.h"
#include <memory>
#include <tuple>
namespace swift {
class AbstractFunctionDecl;
class ASTContext;
class ConcreteDeclRef;
class Decl;
class DeclContext;
class DeclName;
enum class DeclRefKind;
class Expr;
class ExtensionDecl;
class FunctionType;
class LookupResult;
class NominalTypeDecl;
class PatternBindingDecl;
class ProtocolDecl;
class SourceFile;
class SubscriptDecl;
class TopLevelCodeDecl;
class Type;
class ValueDecl;
struct PrintOptions;
/// Typecheck binding initializer at \p bindingIndex.
void typeCheckPatternBinding(PatternBindingDecl *PBD, unsigned bindingIndex);
/// Check if T1 is convertible to T2.
/// \returns true on convertible, false on not.
bool isConvertibleTo(Type T1, Type T2, bool openArchetypes, DeclContext &DC);
void collectDefaultImplementationForProtocolMembers(ProtocolDecl *PD,
llvm::SmallDenseMap<ValueDecl*, ValueDecl*> &DefaultMap);
enum InterestedMemberKind : uint8_t {
struct ResolvedMemberResult {
struct Implementation;
Implementation *Impl;
ResolvedMemberResult(const ResolvedMemberResult &) = delete;
ResolvedMemberResult & operator=(ResolvedMemberResult &) = delete;
ResolvedMemberResult(ResolvedMemberResult &&other) {
Impl = other.Impl;
other.Impl = nullptr;
operator bool() const;
bool hasBestOverload() const;
ValueDecl* getBestOverload() const;
ArrayRef<ValueDecl*> getMemberDecls(InterestedMemberKind Kind);
/// Look up a member with the given name in the given type.
/// Unlike other member lookup functions, \c swift::resolveValueMember()
/// should be used when you want to look up declarations with the same name as
/// one you already have.
ResolvedMemberResult resolveValueMember(DeclContext &DC, Type BaseTy,
DeclName Name);
/// Given a type and an extension to the original type decl of that type,
/// decide if the extension has been applied, i.e. if the requirements of the
/// extension have been fulfilled.
/// \returns True on applied, false on not applied.
bool isExtensionApplied(const DeclContext *DC, Type Ty,
const ExtensionDecl *ED);
/// Given a type and an member value decl , decide if the decl is applied,
/// i.e. if the \c where requirements of the decl have been fulfilled.
/// \returns True on applied, false on not applied.
bool isMemberDeclApplied(const DeclContext *DC, Type Ty, const ValueDecl *VD);
/// The kind of type checking to perform for code completion.
enum class CompletionTypeCheckKind {
/// Type check the expression as normal.
/// Type check the argument to an Objective-C #keyPath.
/// Return the type of an expression parsed during code completion, or
/// None on error.
Optional<Type> getTypeOfCompletionContextExpr(
ASTContext &Ctx,
DeclContext *DC,
CompletionTypeCheckKind kind,
Expr *&parsedExpr,
ConcreteDeclRef &referencedDecl);
/// Resolve type of operator function with \c opName appending it to \c LHS.
/// For \p refKind, use \c DeclRefKind::PostfixOperator for postfix operator,
/// or \c DeclRefKind::BinaryOperator for infix operator.
/// On success, returns resolved function type of the operator. The LHS should
/// already be type-checked. This function guarantees LHS not to be modified.
FunctionType *getTypeOfCompletionOperator(DeclContext *DC, Expr *LHS,
Identifier opName,
DeclRefKind refKind,
ConcreteDeclRef &referencedDecl);
/// Typecheck the given expression.
bool typeCheckExpression(DeclContext *DC, Expr *&parsedExpr);
/// Type check a function body element which is at \p TagetLoc .
bool typeCheckASTNodeAtLoc(DeclContext *DC, SourceLoc TargetLoc);
/// Typecheck top-level code parsed during code completion.
/// \returns true on success, false on error.
bool typeCheckTopLevelCodeDecl(TopLevelCodeDecl *TLCD);
lookupSemanticMember(DeclContext *DC, Type ty, DeclName name);
struct ExtensionInfo {
// The extension with the declarations to apply.
ExtensionDecl *Ext;
// The extension that enables the former to apply, if any (i.e. a
// conditional
// conformance to Foo enables 'extension Foo').
ExtensionDecl *EnablingExt;
bool IsSynthesized;
using ExtensionGroupOperation =
class SynthesizedExtensionAnalyzer {
struct Implementation;
Implementation &Impl;
SynthesizedExtensionAnalyzer(NominalTypeDecl *Target,
PrintOptions Options,
bool IncludeUnconditional = true);
enum class MergeGroupKind : char {
void forEachExtensionMergeGroup(MergeGroupKind Kind,
ExtensionGroupOperation Fn);
bool isInSynthesizedExtension(const ValueDecl *VD);
bool shouldPrintRequirement(ExtensionDecl *ED, StringRef Req);
bool hasMergeGroup(MergeGroupKind Kind);
/// Reported type for an expression. This expression is represented by offset
/// length in the source buffer;
struct ExpressionTypeInfo {
/// The start of the expression;
uint32_t offset;
/// The length of the expression;
uint32_t length;
/// The start of the printed type in a separately given string buffer.
uint32_t typeOffset;
/// The length of the printed type
uint32_t typeLength;
/// The offsets and lengths of all protocols the type conforms to
std::vector<std::pair<uint32_t, uint32_t>> protocols;
/// Collect type information for every expression in \c SF; all types will
/// be printed to \c OS.
ArrayRef<ExpressionTypeInfo> collectExpressionType(SourceFile &SF,
ArrayRef<const char *> ExpectedProtocols,
std::vector<ExpressionTypeInfo> &scratch,
bool CanonicalType,
llvm::raw_ostream &OS);
/// Resolve a list of mangled names to accessible protocol decls from
/// the decl context.
ProtocolDecl *resolveProtocolName(DeclContext *dc, StringRef Name);
/// FIXME: All of the below goes away once CallExpr directly stores its
/// arguments.
/// Return value for getOriginalArgumentList().
struct OriginalArgumentList {
SmallVector<Expr *, 4> args;
SmallVector<Identifier, 4> labels;
SmallVector<SourceLoc, 4> labelLocs;
SourceLoc lParenLoc;
SourceLoc rParenLoc;
bool hasTrailingClosure = false;
/// When applying a solution to a constraint system, the type checker rewrites
/// argument lists of calls to insert default arguments and collect varargs.
/// Sometimes for diagnostics we want to work on the original argument list as
/// written by the user; this performs the reverse transformation.
OriginalArgumentList getOriginalArgumentList(Expr *expr);
/// Returns the root type and result type of the keypath type in a keypath
/// dynamic member lookup subscript, or \c None if it cannot be determined.
/// \param subscript The potential keypath dynamic member lookup subscript.
Type getRootTypeOfKeypathDynamicMember(SubscriptDecl *subscript);
Type getResultTypeOfKeypathDynamicMember(SubscriptDecl *subscript);
/// Collect all the protocol requirements that a given declaration can
/// provide default implementations for. VD is a declaration in extension
/// declaration. Scratch is the buffer to collect those protocol
/// requirements.
/// \returns the slice of Scratch
canDeclProvideDefaultImplementationFor(ValueDecl* VD);
/// Get decls that the given decl overrides, protocol requirements that
/// it serves as a default implementation of, and optionally protocol
/// requirements it satisfies in a conforming class
collectAllOverriddenDecls(ValueDecl *VD,
bool IncludeProtocolRequirements = true,
bool Transitive = false);
/// Enumerates the various kinds of "build" functions within a result
/// builder.
enum class ResultBuilderBuildFunction {
/// Try to infer the component type of a result builder from the type
/// of buildBlock or buildExpression, if it was there.
Type inferResultBuilderComponentType(NominalTypeDecl *builder);
/// Print the declaration for a result builder "build" function, for use
/// in Fix-Its, code completion, and so on.
void printResultBuilderBuildFunction(
NominalTypeDecl *builder, Type componentType,
ResultBuilderBuildFunction function,
Optional<std::string> stubIndent, llvm::raw_ostream &out);
/// Compute the insertion location, indentation string, and component type
/// for a Fix-It that adds a new build* function to a result builder.
std::tuple<SourceLoc, std::string, Type>
determineResultBuilderBuildFixItInfo(NominalTypeDecl *builder);