blob: 5ed768a0072f193d91bf6eccee6152c5d386c08c [file] [log] [blame]
//===--- TypeCheckType.cpp - Type Validation ------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements validation for Swift types, emitting semantic errors as
// appropriate and checking default initializer values.
//
//===----------------------------------------------------------------------===//
#include "TypeChecker.h"
#include "GenericTypeResolver.h"
#include "swift/Strings.h"
#include "swift/AST/ASTVisitor.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/ExprHandle.h"
#include "swift/AST/ForeignErrorConvention.h"
#include "swift/AST/NameLookup.h"
#include "swift/AST/PrettyStackTrace.h"
#include "swift/AST/TypeLoc.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Basic/StringExtras.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
using namespace swift;
GenericTypeResolver::~GenericTypeResolver() { }
Type TypeChecker::getArraySliceType(SourceLoc loc, Type elementType) {
if (!Context.getArrayDecl()) {
diagnose(loc, diag::sugar_type_not_found, 0);
return Type();
}
return ArraySliceType::get(elementType);
}
Type TypeChecker::getDictionaryType(SourceLoc loc, Type keyType,
Type valueType) {
if (!Context.getDictionaryDecl()) {
diagnose(loc, diag::sugar_type_not_found, 3);
return Type();
}
return DictionaryType::get(keyType, valueType);
}
Type TypeChecker::getOptionalType(SourceLoc loc, Type elementType) {
if (!Context.getOptionalDecl()) {
diagnose(loc, diag::sugar_type_not_found, 1);
return Type();
}
return OptionalType::get(elementType);
}
Type TypeChecker::getImplicitlyUnwrappedOptionalType(SourceLoc loc, Type elementType) {
if (!Context.getImplicitlyUnwrappedOptionalDecl()) {
diagnose(loc, diag::sugar_type_not_found, 2);
return Type();
}
return ImplicitlyUnwrappedOptionalType::get(elementType);
}
static Type getStdlibType(TypeChecker &TC, Type &cached, DeclContext *dc,
StringRef name) {
if (cached.isNull()) {
Module *stdlib = TC.Context.getStdlibModule();
LookupTypeResult lookup = TC.lookupMemberType(dc, ModuleType::get(stdlib),
TC.Context.getIdentifier(
name));
if (lookup)
cached = lookup.back().second;
}
return cached;
}
Type TypeChecker::getStringType(DeclContext *dc) {
return ::getStdlibType(*this, StringType, dc, "String");
}
Type TypeChecker::getInt8Type(DeclContext *dc) {
return ::getStdlibType(*this, Int8Type, dc, "Int8");
}
Type TypeChecker::getUInt8Type(DeclContext *dc) {
return ::getStdlibType(*this, UInt8Type, dc, "UInt8");
}
/// Find the standard type of exceptions.
///
/// We call this the "exception type" to try to avoid confusion with
/// the AST's ErrorType node.
Type TypeChecker::getExceptionType(DeclContext *dc, SourceLoc loc) {
if (NominalTypeDecl *decl = Context.getExceptionTypeDecl())
return decl->getDeclaredType();
// Not really sugar, but the actual diagnostic text is fine.
diagnose(loc, diag::sugar_type_not_found, 4);
return Type();
}
static Type getObjectiveCClassType(TypeChecker &TC,
Type &cache,
Identifier ModuleName,
Identifier TypeName,
DeclContext *dc) {
if (cache)
return cache;
auto &Context = TC.Context;
// FIXME: Does not respect visibility of the module.
Module *module = Context.getLoadedModule(ModuleName);
if (!module)
return nullptr;
NameLookupOptions lookupOptions
= defaultMemberLookupOptions | NameLookupFlags::KnownPrivate;
if (auto result = TC.lookupMember(dc, ModuleType::get(module), TypeName,
lookupOptions)) {
for (auto decl : result) {
if (auto nominal = dyn_cast<NominalTypeDecl>(decl.Decl)) {
cache = nominal->getDeclaredType();
return cache;
}
}
}
return nullptr;
}
Type TypeChecker::getNSObjectType(DeclContext *dc) {
return getObjectiveCClassType(*this, NSObjectType, Context.Id_ObjectiveC,
Context.Id_NSObject, dc);
}
Type TypeChecker::getNSErrorType(DeclContext *dc) {
return getObjectiveCClassType(*this, NSObjectType, Context.Id_Foundation,
Context.Id_NSError, dc);
}
Type TypeChecker::getBridgedToObjC(const DeclContext *dc, Type type) {
if (auto bridged = Context.getBridgedToObjC(dc, type, this))
return *bridged;
return nullptr;
}
Type
TypeChecker::getDynamicBridgedThroughObjCClass(DeclContext *dc,
Type dynamicType,
Type valueType) {
// We can only bridge from class or Objective-C existential types.
if (!dynamicType->isObjCExistentialType() &&
!dynamicType->getClassOrBoundGenericClass())
return Type();
// If the value type cannot be bridged, we're done.
if (!valueType->isPotentiallyBridgedValueType())
return Type();
return getBridgedToObjC(dc, valueType);
}
void TypeChecker::forceExternalDeclMembers(NominalTypeDecl *nominalDecl) {
// Force any delayed members added to the nominal type declaration.
if (nominalDecl->hasDelayedMemberDecls()) {
nominalDecl->forceDelayed();
}
if (nominalDecl->hasDelayedMembers()) {
this->handleExternalDecl(nominalDecl);
nominalDecl->setHasDelayedMembers(false);
}
}
Type TypeChecker::resolveTypeInContext(
TypeDecl *typeDecl,
DeclContext *fromDC,
TypeResolutionOptions options,
bool isSpecialized,
GenericTypeResolver *resolver,
UnsatisfiedDependency *unsatisfiedDependency) {
PartialGenericTypeToArchetypeResolver defaultResolver(*this);
if (!resolver)
resolver = &defaultResolver;
// If we have a callback to report dependencies, do so.
if (unsatisfiedDependency &&
(*unsatisfiedDependency)(requestResolveTypeDecl(typeDecl)))
return nullptr;
// If we found a generic parameter, map to the archetype if there is one.
if (auto genericParam = dyn_cast<GenericTypeParamDecl>(typeDecl)) {
return resolver->resolveGenericTypeParamType(
genericParam->getDeclaredType()->castTo<GenericTypeParamType>());
}
// If we are referring to a type within its own context, and we have either
// a generic type with no generic arguments or a non-generic type, use the
// type within the context.
if (auto nominal = dyn_cast<NominalTypeDecl>(typeDecl)) {
forceExternalDeclMembers(nominal);
if (!nominal->getGenericParams() || !isSpecialized) {
for (DeclContext *dc = fromDC; dc; dc = dc->getParent()) {
switch (dc->getContextKind()) {
case DeclContextKind::Module:
case DeclContextKind::FileUnit:
case DeclContextKind::TopLevelCodeDecl:
case DeclContextKind::Initializer:
break;
case DeclContextKind::NominalTypeDecl:
// If this is our nominal type, return its type within its context.
// FIXME: Just produce the type structure when TR_ResolveStructure.
if (cast<NominalTypeDecl>(dc) == nominal)
return resolver->resolveTypeOfContext(nominal);
continue;
case DeclContextKind::ExtensionDecl:
// If this is an extension of our nominal type, return the type
// within the context of its extension.
// FIXME: Just produce the type structure when TR_ResolveStructure.
if (cast<ExtensionDecl>(dc)->getExtendedType()->getAnyNominal()
== nominal)
return resolver->resolveTypeOfContext(dc);
continue;
case DeclContextKind::AbstractClosureExpr:
case DeclContextKind::AbstractFunctionDecl:
case DeclContextKind::SubscriptDecl:
continue;
case DeclContextKind::SerializedLocal:
llvm_unreachable("should not be typechecking deserialized things");
}
break;
}
}
}
// If the type declaration itself is in a non-type context, no type
// substitution is needed.
DeclContext *ownerDC = typeDecl->getDeclContext();
if (!ownerDC->isTypeContext()) {
// FIXME: Just produce the type structure when TR_ResolveStructure.
return typeDecl->getDeclaredType();
}
// Find the nearest enclosing type context around the context from which
// we started our search.
while (!fromDC->isTypeContext()) {
fromDC = fromDC->getParent();
assert(!fromDC->isModuleContext());
}
// If we found an associated type in an inherited protocol, the base
// for our reference to this associated type is our own 'Self'.
auto assocType = dyn_cast<AssociatedTypeDecl>(typeDecl);
if (assocType) {
// If we found an associated type from within its protocol, resolve it
// as a dependent member relative to Self if Self is still dependent.
if (fromDC->isProtocolOrProtocolExtensionContext()) {
auto selfTy = fromDC->getProtocolSelf()->getDeclaredType()
->castTo<GenericTypeParamType>();
auto baseTy = resolver->resolveGenericTypeParamType(selfTy);
if (baseTy->isTypeParameter()) {
return resolver->resolveSelfAssociatedType(baseTy, fromDC, assocType);
}
}
if (typeDecl->getDeclContext() != fromDC) {
if (fromDC->isProtocolOrProtocolExtensionContext()) {
return substMemberTypeWithBase(fromDC->getParentModule(),
typeDecl,
fromDC->getProtocolSelf()
->getArchetype(),
/*isTypeReference=*/true);
}
}
}
// Walk up through the type scopes to find the context where the type
// declaration was found. When we find it, substitute the appropriate base
// type.
auto ownerNominal = ownerDC->isNominalTypeOrNominalTypeExtensionContext();
assert(ownerNominal && "Owner must be a nominal type");
for (auto parentDC = fromDC; !parentDC->isModuleContext();
parentDC = parentDC->getParent()) {
// Skip non-type contexts.
if (!parentDC->isTypeContext())
continue;
// Search the type of this context and its supertypes.
Type superClassOfFromType;
int traversedClassHierarchyDepth = 0;
for (auto fromType = resolver->resolveTypeOfContext(parentDC);
fromType;
fromType = superClassOfFromType) {
// If the nominal type declaration of the context type we're looking at
// matches the owner's nominal type declaration, this is how we found
// the member type declaration. Substitute the type we're coming from as
// the base of the member type to produce the projected type result.
if (fromType->getAnyNominal() == ownerNominal) {
// If we are referring into a protocol or extension thereof,
// the base type is the 'Self'.
if (ownerDC->isProtocolOrProtocolExtensionContext()) {
auto selfTy = ownerDC->getProtocolSelf()->getDeclaredType()
->castTo<GenericTypeParamType>();
fromType = resolver->resolveGenericTypeParamType(selfTy);
}
// Perform the substitution.
return substMemberTypeWithBase(parentDC->getParentModule(), typeDecl,
fromType, /*isTypeReference=*/true);
}
ProtocolConformance *conformance = nullptr;
if (assocType &&
!options.contains(TR_InheritanceClause) &&
conformsToProtocol(fromType,
cast<ProtocolDecl>(assocType->getDeclContext()),
parentDC, ConformanceCheckFlags::Used,
&conformance) &&
conformance) {
return conformance->getTypeWitness(assocType, this).getReplacement();
}
superClassOfFromType = getSuperClassOf(fromType);
/// FIXME: Avoid the possibility of an infinite loop by fixing the root
/// cause instead (incomplete circularity detection).
assert(fromType.getPointer() != superClassOfFromType.getPointer() &&
"Infinite loop due to circular class inheritance.");
assert(traversedClassHierarchyDepth++ <= 16384 &&
"Infinite loop due to circular class inheritance?");
(void) traversedClassHierarchyDepth;
}
}
// Substitute in the appropriate type for 'Self'.
// FIXME: We shouldn't have to guess here; the caller should tell us.
Type fromType;
if (fromDC->isProtocolOrProtocolExtensionContext())
fromType = fromDC->getProtocolSelf()->getArchetype();
else
fromType = resolver->resolveTypeOfContext(fromDC);
// Perform the substitution.
return substMemberTypeWithBase(fromDC->getParentModule(), typeDecl,
fromType, /*isTypeReference=*/true);
}
/// Apply generic arguments to the given type.
Type TypeChecker::applyGenericArguments(Type type,
SourceLoc loc,
DeclContext *dc,
MutableArrayRef<TypeLoc> genericArgs,
bool isGenericSignature,
GenericTypeResolver *resolver) {
// Make sure we always have a resolver to use.
PartialGenericTypeToArchetypeResolver defaultResolver(*this);
if (!resolver)
resolver = &defaultResolver;
auto unbound = type->getAs<UnboundGenericType>();
if (!unbound) {
// FIXME: Highlight generic arguments and introduce a Fix-It to remove
// them.
if (!type->is<ErrorType>()) {
diagnose(loc, diag::not_a_generic_type, type);
}
// Just return the type; this provides better recovery anyway.
return type;
}
// Make sure we have the right number of generic arguments.
// FIXME: If we have fewer arguments than we need, that might be okay, if
// we're allowed to deduce the remaining arguments from context.
auto genericParams = unbound->getDecl()->getGenericParams();
if (genericParams->size() != genericArgs.size()) {
// FIXME: Highlight <...>.
diagnose(loc, diag::type_parameter_count_mismatch,
unbound->getDecl()->getName(),
genericParams->size(), genericArgs.size(),
genericArgs.size() < genericParams->size());
diagnose(unbound->getDecl(), diag::generic_type_declared_here,
unbound->getDecl()->getName());
return nullptr;
}
TypeResolutionOptions options;
if (isGenericSignature)
options |= TR_GenericSignature;
// Validate the generic arguments and capture just the types.
SmallVector<Type, 4> genericArgTypes;
for (auto &genericArg : genericArgs) {
// Validate the generic argument.
if (validateType(genericArg, dc, options, resolver))
return nullptr;
genericArgTypes.push_back(genericArg.getType());
}
// Form the bound generic type
BoundGenericType *BGT = BoundGenericType::get(unbound->getDecl(),
unbound->getParent(),
genericArgTypes);
// Check protocol conformance.
if (!BGT->hasTypeParameter()) {
SourceLoc noteLoc = unbound->getDecl()->getLoc();
if (noteLoc.isInvalid())
noteLoc = loc;
// FIXME: Record that we're checking substitutions, so we can't end up
// with infinite recursion.
// Collect the complete set of generic arguments.
SmallVector<Type, 4> scratch;
ArrayRef<Type> allGenericArgs = BGT->getAllGenericArgs(scratch);
// Check the generic arguments against the generic signature.
auto genericSig = unbound->getDecl()->getGenericSignature();
if (unbound->getDecl()->IsValidatingGenericSignature()) {
diagnose(loc, diag::recursive_requirement_reference);
return BGT;
}
assert(genericSig != nullptr);
if (checkGenericArguments(dc, loc, noteLoc, unbound, genericSig,
allGenericArgs))
return nullptr;
}
return BGT;
}
static Type applyGenericTypeReprArgs(TypeChecker &TC, Type type, SourceLoc loc,
DeclContext *dc,
ArrayRef<TypeRepr *> genericArgs,
bool isGenericSignature,
GenericTypeResolver *resolver) {
SmallVector<TypeLoc, 8> args;
for (auto tyR : genericArgs)
args.push_back(tyR);
Type ty = TC.applyGenericArguments(type, loc, dc, args,
isGenericSignature, resolver);
if (!ty)
return ErrorType::get(TC.Context);
return ty;
}
/// \brief Diagnose a use of an unbound generic type.
static void diagnoseUnboundGenericType(TypeChecker &tc, Type ty,SourceLoc loc) {
tc.diagnose(loc, diag::generic_type_requires_arguments, ty);
auto unbound = ty->castTo<UnboundGenericType>();
tc.diagnose(unbound->getDecl()->getLoc(), diag::generic_type_declared_here,
unbound->getDecl()->getName());
}
/// \brief Returns a valid type or ErrorType in case of an error.
static Type resolveTypeDecl(TypeChecker &TC, TypeDecl *typeDecl, SourceLoc loc,
DeclContext *dc,
ArrayRef<TypeRepr *> genericArgs,
TypeResolutionOptions options,
GenericTypeResolver *resolver,
UnsatisfiedDependency *unsatisfiedDependency) {
assert(dc && "No declaration context for type resolution?");
// If we have a callback to report dependencies, do so.
if (unsatisfiedDependency) {
if ((*unsatisfiedDependency)(requestResolveTypeDecl(typeDecl)))
return nullptr;
} else {
// Validate the declaration.
TC.validateDecl(typeDecl);
}
// Resolve the type declaration to a specific type. How this occurs
// depends on the current context and where the type was found.
Type type = TC.resolveTypeInContext(typeDecl, dc, options,
!genericArgs.empty(), resolver);
// FIXME: Defensive check that shouldn't be needed, but prevents a
// huge number of crashes on ill-formed code.
if (!type)
return ErrorType::get(TC.Context);
if (type->is<UnboundGenericType>() && genericArgs.empty() &&
!options.contains(TR_AllowUnboundGenerics) &&
!options.contains(TR_ResolveStructure)) {
diagnoseUnboundGenericType(TC, type, loc);
return ErrorType::get(TC.Context);
}
// If we found a generic parameter, try to resolve it.
// FIXME: Jump through hoops to maintain syntactic sugar. We shouldn't care
// about this, because we shouldn't have to do this at all.
if (auto genericParam = type->getAs<GenericTypeParamType>()) {
auto resolvedGP = resolver->resolveGenericTypeParamType(genericParam);
if (auto substituted = dyn_cast<SubstitutedType>(type.getPointer())) {
type = SubstitutedType::get(substituted->getOriginal(), resolvedGP,
TC.Context);
} else {
type = resolvedGP;
}
}
if (!genericArgs.empty() && !options.contains(TR_ResolveStructure)) {
// Apply the generic arguments to the type.
type = applyGenericTypeReprArgs(TC, type, loc, dc, genericArgs,
options.contains(TR_GenericSignature),
resolver);
}
assert(type);
return type;
}
/// Retrieve the nearest enclosing nominal type context.
static NominalTypeDecl *getEnclosingNominalContext(DeclContext *dc) {
while (dc->isLocalContext())
dc = dc->getParent();
if (auto nominal = dc->isNominalTypeOrNominalTypeExtensionContext())
return nominal;
return nullptr;
}
/// Diagnose a reference to an unknown type.
///
/// This routine diagnoses a reference to an unknown type, and
/// attempts to fix the reference via various means.
///
/// \param tc The type checker through which we should emit the diagnostic.
/// \param dc The context in which name lookup occurred.
///
/// \returns either the corrected type, if possible, or an error type to
/// that correction failed.
static Type diagnoseUnknownType(TypeChecker &tc, DeclContext *dc,
Type parentType,
SourceRange parentRange,
ComponentIdentTypeRepr *comp,
TypeResolutionOptions options,
GenericTypeResolver *resolver,
UnsatisfiedDependency *unsatisfiedDependency) {
// Unqualified lookup case.
if (parentType.isNull()) {
// Attempt to refer to 'Self' within a non-protocol nominal
// type. Fix this by replacing 'Self' with the nominal type name.
NominalTypeDecl *nominal = nullptr;
if (comp->getIdentifier() == tc.Context.Id_Self &&
!isa<GenericIdentTypeRepr>(comp) &&
(nominal = getEnclosingNominalContext(dc))) {
// Retrieve the nominal type and resolve it within this context.
assert(!isa<ProtocolDecl>(nominal) && "Cannot be a protocol");
auto type = resolveTypeDecl(tc, nominal, comp->getIdLoc(), dc, { },
options, resolver, unsatisfiedDependency);
if (type->is<ErrorType>())
return type;
// Produce a Fix-It replacing 'Self' with the nominal type name.
tc.diagnose(comp->getIdLoc(), diag::self_in_nominal, nominal->getName())
.fixItReplace(comp->getIdLoc(), nominal->getName().str());
comp->overwriteIdentifier(nominal->getName());
comp->setValue(nominal);
return type;
}
// Fallback.
SourceLoc L = comp->getIdLoc();
SourceRange R = SourceRange(comp->getIdLoc());
// Check if the unknown type is in the type remappings.
auto &Remapped = tc.Context.RemappedTypes;
auto TypeName = comp->getIdentifier().str();
auto I = Remapped.find(TypeName);
if (I != Remapped.end()) {
auto RemappedTy = I->second->getString();
tc.diagnose(L, diag::use_undeclared_type_did_you_mean,
comp->getIdentifier(), RemappedTy)
.highlight(R)
.fixItReplace(R, RemappedTy);
// Replace the computed type with the suggested type.
comp->overwriteIdentifier(tc.Context.getIdentifier(RemappedTy));
// HACK: 'NSUInteger' suggests both 'UInt' and 'Int'.
if (TypeName == "NSUInteger") {
tc.diagnose(L, diag::note_remapped_type, "UInt")
.fixItReplace(R, "UInt");
}
return I->second;
}
tc.diagnose(L, diag::use_undeclared_type,
comp->getIdentifier())
.highlight(R);
return ErrorType::get(tc.Context);
}
// Qualified lookup case.
// FIXME: Typo correction!
// Lookup into a type.
if (auto moduleType = parentType->getAs<ModuleType>()) {
tc.diagnose(comp->getIdLoc(), diag::no_module_type,
comp->getIdentifier(), moduleType->getModule()->getName());
} else {
tc.diagnose(comp->getIdLoc(), diag::invalid_member_type,
comp->getIdentifier(), parentType)
.highlight(parentRange);
}
return ErrorType::get(tc.Context);
}
/// Resolve the given identifier type representation as an unqualified type,
/// returning the type it references.
///
/// \returns Either the resolved type or a null type, the latter of
/// which indicates that some dependencies were unsatisfied.
static Type
resolveTopLevelIdentTypeComponent(TypeChecker &TC, DeclContext *DC,
ComponentIdentTypeRepr *comp,
TypeResolutionOptions options,
bool diagnoseErrors,
GenericTypeResolver *resolver,
UnsatisfiedDependency *unsatisfiedDependency){
// Short-circuiting.
if (comp->isInvalid()) return ErrorType::get(TC.Context);
// If the component has already been bound to a declaration, handle
// that now.
if (ValueDecl *VD = comp->getBoundDecl()) {
// Diagnose non-type declarations.
auto typeDecl = dyn_cast<TypeDecl>(VD);
if (!typeDecl) {
if (diagnoseErrors) {
TC.diagnose(comp->getIdLoc(), diag::use_non_type_value, VD->getName());
TC.diagnose(VD, diag::use_non_type_value_prev, VD->getName());
}
comp->setInvalid();
return ErrorType::get(TC.Context);
}
// Retrieve the generic arguments, if there are any.
ArrayRef<TypeRepr *> genericArgs;
if (auto genComp = dyn_cast<GenericIdentTypeRepr>(comp))
genericArgs = genComp->getGenericArgs();
// Resolve the type declaration within this context.
return resolveTypeDecl(TC, typeDecl, comp->getIdLoc(), DC,
genericArgs, options, resolver,
unsatisfiedDependency);
}
// Resolve the first component, which is the only one that requires
// unqualified name lookup.
DeclContext *lookupDC = DC;
// Dynamic 'Self' in the result type of a function body.
if (options.contains(TR_DynamicSelfResult) &&
comp->getIdentifier() == TC.Context.Id_Self) {
auto func = cast<FuncDecl>(DC);
assert(func->hasDynamicSelf() && "Not marked as having dynamic Self?");
return func->getDynamicSelf();
}
// For lookups within the generic signature, look at the generic
// parameters (only), then move up to the enclosing context.
if (options.contains(TR_GenericSignature)) {
GenericParamList *genericParams;
if (auto *nominal = dyn_cast<NominalTypeDecl>(DC)) {
genericParams = nominal->getGenericParams();
} else if (auto *ext = dyn_cast<ExtensionDecl>(DC)) {
genericParams = ext->getGenericParams();
} else {
genericParams = cast<AbstractFunctionDecl>(DC)->getGenericParams();
}
if (genericParams) {
auto matchingParam =
std::find_if(genericParams->begin(), genericParams->end(),
[comp](const GenericTypeParamDecl *param) {
return param->getFullName().matchesRef(comp->getIdentifier());
});
if (matchingParam != genericParams->end()) {
comp->setValue(*matchingParam);
return resolveTopLevelIdentTypeComponent(TC, DC, comp, options,
diagnoseErrors, resolver,
unsatisfiedDependency);
}
}
// If the lookup occurs from within a trailing 'where' clause of
// a constrained extension, also look for associated types.
if (genericParams && genericParams->hasTrailingWhereClause() &&
isa<ExtensionDecl>(DC) && comp->getIdLoc().isValid() &&
TC.Context.SourceMgr.rangeContainsTokenLoc(
genericParams->getTrailingWhereClauseSourceRange(),
comp->getIdLoc())) {
// We need to be able to perform qualified lookup into the given
// declaration context.
if (unsatisfiedDependency &&
(*unsatisfiedDependency)(
requestQualifiedLookupInDeclContext({ DC, comp->getIdentifier(),
comp->getIdLoc() })))
return nullptr;
auto nominal = DC->isNominalTypeOrNominalTypeExtensionContext();
SmallVector<ValueDecl *, 4> decls;
if (DC->lookupQualified(nominal->getDeclaredInterfaceType(),
comp->getIdentifier(),
NL_QualifiedDefault|NL_ProtocolMembers,
&TC,
decls)) {
for (const auto decl : decls) {
// FIXME: Better ambiguity handling.
if (auto assocType = dyn_cast<AssociatedTypeDecl>(decl)) {
comp->setValue(assocType);
return resolveTopLevelIdentTypeComponent(TC, DC, comp, options,
diagnoseErrors, resolver,
unsatisfiedDependency);
}
}
}
}
if (!DC->isCascadingContextForLookup(/*excludeFunctions*/true))
options |= TR_KnownNonCascadingDependency;
// The remaining lookups will be in the parent context.
lookupDC = DC->getParent();
}
// We need to be able to perform unqualified lookup into the given
// declaration context.
if (unsatisfiedDependency &&
(*unsatisfiedDependency)(
requestUnqualifiedLookupInDeclContext({ lookupDC,
comp->getIdentifier(),
comp->getIdLoc() })))
return nullptr;
NameLookupOptions lookupOptions = defaultUnqualifiedLookupOptions;
lookupOptions |= NameLookupFlags::OnlyTypes;
if (options.contains(TR_KnownNonCascadingDependency))
lookupOptions |= NameLookupFlags::KnownPrivate;
// FIXME: Eliminate this once we can handle finding protocol members
// in resolveTypeInContext.
lookupOptions -= NameLookupFlags::ProtocolMembers;
LookupResult globals = TC.lookupUnqualified(lookupDC, comp->getIdentifier(),
comp->getIdLoc(), lookupOptions);
// Process the names we found.
Type current;
TypeDecl *currentDecl = nullptr;
bool isAmbiguous = false;
for (const auto &result : globals) {
// Ignore non-type declarations.
auto typeDecl = dyn_cast<TypeDecl>(result.Decl);
if (!typeDecl)
continue;
// If necessary, add delayed members to the declaration.
if (auto nomDecl = dyn_cast<NominalTypeDecl>(typeDecl)) {
TC.forceExternalDeclMembers(nomDecl);
}
ArrayRef<TypeRepr *> genericArgs;
if (auto genComp = dyn_cast<GenericIdentTypeRepr>(comp))
genericArgs = genComp->getGenericArgs();
Type type = resolveTypeDecl(TC, typeDecl, comp->getIdLoc(),
DC, genericArgs, options, resolver,
unsatisfiedDependency);
if (!type || type->is<ErrorType>())
return type;
// If this is the first result we found, record it.
if (current.isNull()) {
current = type;
currentDecl = typeDecl;
continue;
}
// Otherwise, check for an ambiguity.
if (!current->isEqual(type)) {
isAmbiguous = true;
break;
}
// We have a found multiple type aliases that refer to the same thing.
// Ignore the duplicate.
}
// Complain about any ambiguities we detected.
// FIXME: We could recover by looking at later components.
if (isAmbiguous) {
if (diagnoseErrors) {
TC.diagnose(comp->getIdLoc(), diag::ambiguous_type_base,
comp->getIdentifier())
.highlight(comp->getIdLoc());
for (auto result : globals) {
TC.diagnose(result.Decl, diag::found_candidate);
}
}
comp->setInvalid();
return ErrorType::get(TC.Context);
}
// If we found nothing, complain and give ourselves a chance to recover.
if (current.isNull()) {
// If we're not allowed to complain or we couldn't fix the
// source, bail out.
if (!diagnoseErrors)
return ErrorType::get(TC.Context);
return diagnoseUnknownType(TC, DC, nullptr, SourceRange(), comp, options,
resolver, unsatisfiedDependency);
}
comp->setValue(currentDecl);
return current;
}
/// Resolve the given identifier type representation as a qualified
/// lookup within the given parent type, returning the type it
/// references.
static Type resolveNestedIdentTypeComponent(
TypeChecker &TC, DeclContext *DC,
Type parentTy,
SourceRange parentRange,
ComponentIdentTypeRepr *comp,
TypeResolutionOptions options,
bool diagnoseErrors,
GenericTypeResolver *resolver,
UnsatisfiedDependency *unsatisfiedDependency) {
// Short-circuiting.
if (comp->isInvalid()) return ErrorType::get(TC.Context);
// If a declaration has already been bound, use it.
if (ValueDecl *decl = comp->getBoundDecl()) {
// Make sure we have a type declaration.
auto typeDecl = dyn_cast<TypeDecl>(decl);
if (!typeDecl) {
if (diagnoseErrors) {
TC.diagnose(comp->getIdLoc(), diag::use_non_type_value,
decl->getName());
TC.diagnose(decl, diag::use_non_type_value_prev,
decl->getName());
}
comp->setInvalid();
return ErrorType::get(TC.Context);
}
Type memberType;
if (parentTy->isTypeParameter()) {
// If the parent is a type parameter, the member is a dependent member.
// FIXME: We either have an associated type here or a member of
// some member of the superclass bound (or its superclasses),
// which should allow us to skip much of the work in
// resolveDependentMemberType.
// Try to resolve the dependent member type to a specific associated
// type.
memberType = resolver->resolveDependentMemberType(parentTy, DC,
parentRange, comp);
assert(memberType && "Received null dependent member type");
} else if (isa<AssociatedTypeDecl>(typeDecl) &&
!parentTy->is<ArchetypeType>() &&
!parentTy->isExistentialType()) {
auto assocType = cast<AssociatedTypeDecl>(typeDecl);
// Find the conformance and dig out the type witness.
ConformanceCheckOptions conformanceOptions;
if (options.contains(TR_InExpression))
conformanceOptions |= ConformanceCheckFlags::InExpression;
auto *protocol = cast<ProtocolDecl>(assocType->getDeclContext());
ProtocolConformance *conformance = nullptr;
if (!TC.conformsToProtocol(parentTy, protocol, DC, conformanceOptions,
&conformance) ||
!conformance) {
return nullptr;
}
// FIXME: Establish that we need a type witness.
return conformance->getTypeWitness(assocType, &TC).getReplacement();
} else {
// Otherwise, simply substitute the parent type into the member.
memberType = TC.substMemberTypeWithBase(DC->getParentModule(), typeDecl,
parentTy,
/*isTypeReference=*/true);
}
// Propagate failure.
if (!memberType || memberType->is<ErrorType>()) return memberType;
// If there are generic arguments, apply them now.
if (auto genComp = dyn_cast<GenericIdentTypeRepr>(comp)) {
memberType = applyGenericTypeReprArgs(
TC, memberType, comp->getIdLoc(), DC,
genComp->getGenericArgs(),
options.contains(TR_GenericSignature),
resolver);
// Propagate failure.
if (!memberType || memberType->is<ErrorType>()) return memberType;
}
// We're done.
return memberType;
}
// If the parent is a dependent type, the member is a dependent member.
if (parentTy->isTypeParameter()) {
// Try to resolve the dependent member type to a specific associated
// type.
Type memberType = resolver->resolveDependentMemberType(parentTy, DC,
parentRange,
comp);
assert(memberType && "Received null dependent member type");
if (isa<GenericIdentTypeRepr>(comp) && !memberType->is<ErrorType>()) {
// FIXME: Highlight generic arguments and introduce a Fix-It to
// remove them.
if (diagnoseErrors)
TC.diagnose(comp->getIdLoc(), diag::not_a_generic_type, memberType);
// Drop the arguments.
}
// If we know what type declaration we're referencing, store it.
if (auto typeDecl = memberType->getDirectlyReferencedTypeDecl()) {
comp->setValue(typeDecl);
}
return memberType;
}
// Look for member types with the given name.
bool isKnownNonCascading = options.contains(TR_KnownNonCascadingDependency);
if (!isKnownNonCascading && options.contains(TR_InExpression)) {
// Expressions cannot affect a function's signature.
isKnownNonCascading = isa<AbstractFunctionDecl>(DC);
}
// We need to be able to perform qualified lookup into the given type.
if (unsatisfiedDependency) {
DeclContext *dc;
if (auto parentNominal = parentTy->getAnyNominal())
dc = parentNominal;
else if (auto parentModule = parentTy->getAs<ModuleType>())
dc = parentModule->getModule();
else
dc = nullptr;
if (dc &&
(*unsatisfiedDependency)(
requestQualifiedLookupInDeclContext({ dc, comp->getIdentifier(),
comp->getIdLoc() })))
return nullptr;
}
NameLookupOptions lookupOptions = defaultMemberLookupOptions;
if (isKnownNonCascading)
lookupOptions |= NameLookupFlags::KnownPrivate;
if (options.contains(TR_ExtensionBinding))
lookupOptions -= NameLookupFlags::ProtocolMembers;
auto memberTypes = TC.lookupMemberType(DC, parentTy, comp->getIdentifier(),
lookupOptions);
// Name lookup was ambiguous. Complain.
// FIXME: Could try to apply generic arguments first, and see whether
// that resolves things. But do we really want that to succeed?
if (memberTypes.size() > 1) {
if (diagnoseErrors)
TC.diagnoseAmbiguousMemberType(parentTy, parentRange,
comp->getIdentifier(), comp->getIdLoc(),
memberTypes);
return ErrorType::get(TC.Context);
}
// If we didn't find anything, complain.
bool recovered = false;
Type memberType;
TypeDecl *member = nullptr;
if (!memberTypes) {
// If we're not allowed to complain or we couldn't fix the
// source, bail out.
if (!diagnoseErrors) {
return ErrorType::get(TC.Context);
}
Type ty = diagnoseUnknownType(TC, DC, parentTy, parentRange, comp, options,
resolver, unsatisfiedDependency);
if (!ty || ty->is<ErrorType>()) {
return ErrorType::get(TC.Context);
}
recovered = true;
memberType = ty;
member = cast_or_null<TypeDecl>(comp->getBoundDecl());
} else {
memberType = memberTypes.back().second;
member = memberTypes.back().first;
}
if (parentTy->isExistentialType()) {
if (diagnoseErrors)
TC.diagnose(comp->getIdLoc(), diag::assoc_type_outside_of_protocol,
comp->getIdentifier());
return ErrorType::get(TC.Context);
}
// If there are generic arguments, apply them now.
if (auto genComp = dyn_cast<GenericIdentTypeRepr>(comp))
memberType = applyGenericTypeReprArgs(
TC, memberType, comp->getIdLoc(), DC, genComp->getGenericArgs(),
options.contains(TR_GenericSignature), resolver);
if (member)
comp->setValue(member);
return memberType;
}
static Type resolveIdentTypeComponent(
TypeChecker &TC, DeclContext *DC,
ArrayRef<ComponentIdentTypeRepr *> components,
TypeResolutionOptions options,
bool diagnoseErrors,
GenericTypeResolver *resolver,
UnsatisfiedDependency *unsatisfiedDependency) {
auto comp = components.back();
// The first component uses unqualified lookup.
auto parentComps = components.slice(0, components.size()-1);
if (parentComps.empty()) {
return resolveTopLevelIdentTypeComponent(TC, DC, comp, options,
diagnoseErrors, resolver,
unsatisfiedDependency);
}
// All remaining components use qualified lookup.
// Resolve the parent type.
Type parentTy = resolveIdentTypeComponent(TC, DC, parentComps, options,
diagnoseErrors, resolver,
unsatisfiedDependency);
if (!parentTy || parentTy->is<ErrorType>()) return parentTy;
// Resolve the nested type.
SourceRange parentRange(parentComps.front()->getIdLoc(),
parentComps.back()->getSourceRange().End);
return resolveNestedIdentTypeComponent(TC, DC, parentTy,
parentRange, comp,
options, diagnoseErrors,
resolver,
unsatisfiedDependency);
}
// FIXME: Merge this with diagAvailability in MiscDiagnostics.cpp.
static bool checkTypeDeclAvailability(Decl *TypeDecl, IdentTypeRepr *IdType,
SourceLoc Loc, DeclContext *DC,
TypeChecker &TC,
bool AllowPotentiallyUnavailableProtocol) {
if (auto CI = dyn_cast<ComponentIdentTypeRepr>(IdType)) {
if (auto Attr = AvailableAttr::isUnavailable(TypeDecl)) {
switch (Attr->getUnconditionalAvailability()) {
case UnconditionalAvailabilityKind::None:
case UnconditionalAvailabilityKind::Deprecated:
break;
case UnconditionalAvailabilityKind::Unavailable:
if (!Attr->Rename.empty()) {
TC.diagnose(Loc, diag::availability_decl_unavailable_rename,
CI->getIdentifier(), Attr->Rename)
.fixItReplace(Loc, Attr->Rename);
} else if (Attr->Message.empty()) {
TC.diagnose(Loc, diag::availability_decl_unavailable,
CI->getIdentifier())
.highlight(Loc);
} else {
EncodedDiagnosticMessage EncodedMessage(Attr->Message);
TC.diagnose(Loc, diag::availability_decl_unavailable_msg,
CI->getIdentifier(), EncodedMessage.Message)
.highlight(Loc);
}
break;
case UnconditionalAvailabilityKind::UnavailableInSwift:
if (Attr->Message.empty()) {
TC.diagnose(Loc, diag::availability_decl_unavailable_in_swift,
CI->getIdentifier())
.highlight(Loc);
} else {
EncodedDiagnosticMessage EncodedMessage(Attr->Message);
TC.diagnose(Loc, diag::availability_decl_unavailable_in_swift_msg,
CI->getIdentifier(), EncodedMessage.Message)
.highlight(Loc);
}
break;
}
auto DLoc = TypeDecl->getLoc();
if (DLoc.isValid())
TC.diagnose(DLoc, diag::availability_marked_unavailable,
CI->getIdentifier()).highlight(Attr->getRange());
return true;
}
if (auto *Attr = TypeChecker::getDeprecated(TypeDecl)) {
TC.diagnoseDeprecated(CI->getSourceRange(), DC, Attr,
CI->getIdentifier());
}
if (AllowPotentiallyUnavailableProtocol && isa<ProtocolDecl>(TypeDecl))
return false;
// Check for potential unavailability because of the minimum
// deployment version.
// We should probably unify this checking for deployment-version API
// unavailability with checking for explicitly annotated unavailability.
Optional<UnavailabilityReason> Unavail =
TC.checkDeclarationAvailability(TypeDecl, Loc, DC);
if (Unavail.hasValue()) {
TC.diagnosePotentialUnavailability(TypeDecl, CI->getIdentifier(),
CI->getSourceRange(), DC,
Unavail.getValue());
}
}
return false;
}
static bool diagnoseAvailability(Type ty, IdentTypeRepr *IdType, SourceLoc Loc,
DeclContext *DC, TypeChecker &TC,
bool AllowPotentiallyUnavailableProtocol) {
if (auto *NAT = dyn_cast<NameAliasType>(ty.getPointer())) {
if (checkTypeDeclAvailability(NAT->getDecl(), IdType, Loc, DC, TC,
AllowPotentiallyUnavailableProtocol))
return true;
}
// Look through substituted types to diagnose when the original
// type is marked unavailable.
if (auto *ST = dyn_cast<SubstitutedType>(ty.getPointer())) {
if (diagnoseAvailability(ST->getOriginal(), IdType, Loc, DC, TC,
AllowPotentiallyUnavailableProtocol)) {
return true;
}
}
CanType canTy = ty.getCanonicalTypeOrNull();
if (canTy.isNull())
return false;
if (auto NTD = canTy.getAnyNominal())
return checkTypeDeclAvailability(NTD, IdType, Loc, DC, TC,
AllowPotentiallyUnavailableProtocol);
return false;
}
/// \brief Returns a valid type or ErrorType in case of an error.
Type TypeChecker::resolveIdentifierType(
DeclContext *DC,
IdentTypeRepr *IdType,
TypeResolutionOptions options,
bool diagnoseErrors,
GenericTypeResolver *resolver,
UnsatisfiedDependency *unsatisfiedDependency) {
assert(resolver && "Missing generic type resolver");
auto ComponentRange = IdType->getComponentRange();
auto Components = llvm::makeArrayRef(ComponentRange.begin(),
ComponentRange.end());
Type result = resolveIdentTypeComponent(*this, DC, Components, options,
diagnoseErrors, resolver,
unsatisfiedDependency);
if (!result) return nullptr;
if (auto moduleTy = result->getAs<ModuleType>()) {
if (diagnoseErrors) {
auto moduleName = moduleTy->getModule()->getName();
diagnose(Components.back()->getIdLoc(),
diag::use_undeclared_type, moduleName);
diagnose(Components.back()->getIdLoc(),
diag::note_module_as_type, moduleName);
}
Components.back()->setInvalid();
return ErrorType::get(Context);
}
// We allow a type to conform to a protocol that is less available than
// the type itself. This enables a type to retroactively model or directly
// conform to a protocol only available on newer OSes and yet still be used on
// older OSes.
// To support this, inside inheritance clauses we allow references to
// protocols that are unavailable in the current type refinement context.
bool AllowPotentiallyUnavailableProtocol =
options.contains(TR_InheritanceClause);
// Check the availability of the type. Skip checking for SIL.
if (!(options & TR_SILType) && !(options & TR_AllowUnavailable) &&
diagnoseAvailability(result, IdType,
Components.back()->getIdLoc(), DC, *this,
AllowPotentiallyUnavailableProtocol)) {
Components.back()->setInvalid();
return ErrorType::get(Context);
}
return result;
}
bool TypeChecker::validateType(TypeLoc &Loc, DeclContext *DC,
TypeResolutionOptions options,
GenericTypeResolver *resolver,
UnsatisfiedDependency *unsatisfiedDependency) {
// FIXME: Verify that these aren't circular and infinite size.
// If we've already validated this type, don't do so again.
if (Loc.wasValidated())
return Loc.isError();
if (Loc.getType().isNull()) {
auto type = resolveType(Loc.getTypeRepr(), DC, options, resolver,
unsatisfiedDependency);
if (!type) {
// If a dependency went unsatisfied, just return false.
if (unsatisfiedDependency) return false;
type = ErrorType::get(Context);
}
Loc.setType(type, true);
return Loc.isError();
}
Loc.setType(Loc.getType(), true);
return Loc.isError();
}
namespace {
const auto DefaultParameterConvention = ParameterConvention::Direct_Unowned;
const auto DefaultResultConvention = ResultConvention::Unowned;
class TypeResolver {
TypeChecker &TC;
ASTContext &Context;
DeclContext *DC;
GenericTypeResolver *Resolver;
swift::UnsatisfiedDependency *UnsatisfiedDependency;
public:
TypeResolver(TypeChecker &tc, DeclContext *DC,
GenericTypeResolver *resolver,
swift::UnsatisfiedDependency *unsatisfiedDependency)
: TC(tc), Context(tc.Context), DC(DC), Resolver(resolver),
UnsatisfiedDependency(unsatisfiedDependency)
{
assert(resolver);
}
Type resolveType(TypeRepr *repr, TypeResolutionOptions options);
private:
Type resolveAttributedType(AttributedTypeRepr *repr,
TypeResolutionOptions options);
Type resolveAttributedType(TypeAttributes &attrs, TypeRepr *repr,
TypeResolutionOptions options);
Type resolveASTFunctionType(FunctionTypeRepr *repr,
TypeResolutionOptions options,
FunctionType::ExtInfo extInfo
= FunctionType::ExtInfo());
Type resolveSILFunctionType(FunctionTypeRepr *repr,
TypeResolutionOptions options,
SILFunctionType::ExtInfo extInfo
= SILFunctionType::ExtInfo(),
ParameterConvention calleeConvention
= DefaultParameterConvention);
SILParameterInfo resolveSILParameter(TypeRepr *repr,
TypeResolutionOptions options);
bool resolveSILResults(TypeRepr *repr, TypeResolutionOptions options,
SmallVectorImpl<SILResultInfo> &results,
Optional<SILResultInfo> &errorResult);
bool resolveSingleSILResult(TypeRepr *repr, TypeResolutionOptions options,
SmallVectorImpl<SILResultInfo> &results,
Optional<SILResultInfo> &errorResult);
Type resolveInOutType(InOutTypeRepr *repr,
TypeResolutionOptions options);
Type resolveArrayType(ArrayTypeRepr *repr,
TypeResolutionOptions options);
Type resolveDictionaryType(DictionaryTypeRepr *repr,
TypeResolutionOptions options);
Type resolveOptionalType(OptionalTypeRepr *repr,
TypeResolutionOptions options);
Type resolveImplicitlyUnwrappedOptionalType(ImplicitlyUnwrappedOptionalTypeRepr *repr,
TypeResolutionOptions options);
Type resolveTupleType(TupleTypeRepr *repr,
TypeResolutionOptions options);
Type resolveProtocolCompositionType(ProtocolCompositionTypeRepr *repr,
TypeResolutionOptions options);
Type resolveMetatypeType(MetatypeTypeRepr *repr,
TypeResolutionOptions options);
Type resolveProtocolType(ProtocolTypeRepr *repr,
TypeResolutionOptions options);
Type buildMetatypeType(MetatypeTypeRepr *repr,
Type instanceType,
Optional<MetatypeRepresentation> storedRepr);
Type buildProtocolType(ProtocolTypeRepr *repr,
Type instanceType,
Optional<MetatypeRepresentation> storedRepr);
};
}
Type TypeChecker::resolveType(TypeRepr *TyR, DeclContext *DC,
TypeResolutionOptions options,
GenericTypeResolver *resolver,
UnsatisfiedDependency *unsatisfiedDependency) {
PrettyStackTraceTypeRepr stackTrace(Context, "resolving", TyR);
// Make sure we always have a resolver to use.
PartialGenericTypeToArchetypeResolver defaultResolver(*this);
if (!resolver)
resolver = &defaultResolver;
TypeResolver typeResolver(*this, DC, resolver, unsatisfiedDependency);
auto result = typeResolver.resolveType(TyR, options);
// If we resolved down to an error, make sure to mark the typeRepr as invalid
// so we don't produce a redundant diagnostic.
if (result && result->is<ErrorType>())
TyR->setInvalid();
return result;
}
Type TypeResolver::resolveType(TypeRepr *repr, TypeResolutionOptions options) {
assert(repr && "Cannot validate null TypeReprs!");
// If we know the type representation is invalid, just return an
// error type.
if (repr->isInvalid()) return ErrorType::get(TC.Context);
// Strip the "is function input" bits unless this is a type that knows about
// them.
if (!isa<InOutTypeRepr>(repr) && !isa<TupleTypeRepr>(repr)) {
options -= TR_ImmediateFunctionInput;
options -= TR_FunctionInput;
}
switch (repr->getKind()) {
case TypeReprKind::Error:
return ErrorType::get(Context);
case TypeReprKind::Attributed:
return resolveAttributedType(cast<AttributedTypeRepr>(repr), options);
case TypeReprKind::InOut:
return resolveInOutType(cast<InOutTypeRepr>(repr), options);
case TypeReprKind::SimpleIdent:
case TypeReprKind::GenericIdent:
case TypeReprKind::CompoundIdent:
return TC.resolveIdentifierType(DC, cast<IdentTypeRepr>(repr), options,
/*diagnoseErrors*/ true, Resolver,
UnsatisfiedDependency);
case TypeReprKind::Function:
if (!(options & TR_SILType))
return resolveASTFunctionType(cast<FunctionTypeRepr>(repr), options);
return resolveSILFunctionType(cast<FunctionTypeRepr>(repr), options);
case TypeReprKind::Array:
return resolveArrayType(cast<ArrayTypeRepr>(repr), options);
case TypeReprKind::Dictionary:
return resolveDictionaryType(cast<DictionaryTypeRepr>(repr), options);
case TypeReprKind::Optional:
return resolveOptionalType(cast<OptionalTypeRepr>(repr), options);
case TypeReprKind::ImplicitlyUnwrappedOptional:
return resolveImplicitlyUnwrappedOptionalType(
cast<ImplicitlyUnwrappedOptionalTypeRepr>(repr),
options);
case TypeReprKind::Tuple:
return resolveTupleType(cast<TupleTypeRepr>(repr), options);
case TypeReprKind::Named:
llvm_unreachable("NamedTypeRepr only shows up as an element of Tuple");
case TypeReprKind::ProtocolComposition:
return resolveProtocolCompositionType(
cast<ProtocolCompositionTypeRepr>(repr),
options);
case TypeReprKind::Metatype:
return resolveMetatypeType(cast<MetatypeTypeRepr>(repr), options);
case TypeReprKind::Protocol:
return resolveProtocolType(cast<ProtocolTypeRepr>(repr), options);
case TypeReprKind::Fixed:
return cast<FixedTypeRepr>(repr)->getType();
}
llvm_unreachable("all cases should be handled");
}
Type TypeResolver::resolveAttributedType(AttributedTypeRepr *repr,
TypeResolutionOptions options) {
// Copy the attributes, since we're about to start hacking on them.
TypeAttributes attrs = repr->getAttrs();
assert(!attrs.empty());
return resolveAttributedType(attrs, repr->getTypeRepr(), options);
}
Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
TypeRepr *repr,
TypeResolutionOptions options) {
// The type we're working with, in case we want to build it differently
// based on the attributes we see.
Type ty;
// In SIL *only*, allow @thin, @thick, or @objc_metatype to apply to
// a metatype.
if (attrs.has(TAK_thin) || attrs.has(TAK_thick) ||
attrs.has(TAK_objc_metatype)) {
if (auto SF = DC->getParentSourceFile()) {
if (SF->Kind == SourceFileKind::SIL) {
TypeRepr *base;
if (auto metatypeRepr = dyn_cast<MetatypeTypeRepr>(repr)) {
base = metatypeRepr->getBase();
} else if (auto protocolRepr = dyn_cast<ProtocolTypeRepr>(repr)) {
base = protocolRepr->getBase();
} else {
base = nullptr;
}
if (base) {
Optional<MetatypeRepresentation> storedRepr;
// The instance type is not a SIL type. We still want to allow
// unavailable references, though.
auto instanceOptions = options - TR_SILType | TR_AllowUnavailable;
auto instanceTy = resolveType(base, instanceOptions);
if (!instanceTy || instanceTy->is<ErrorType>())
return instanceTy;
// Check for @thin.
if (attrs.has(TAK_thin)) {
storedRepr = MetatypeRepresentation::Thin;
attrs.clearAttribute(TAK_thin);
}
// Check for @thick.
if (attrs.has(TAK_thick)) {
if (storedRepr)
TC.diagnose(repr->getStartLoc(),
diag::sil_metatype_multiple_reprs);
storedRepr = MetatypeRepresentation::Thick;
attrs.clearAttribute(TAK_thick);
}
// Check for @objc_metatype.
if (attrs.has(TAK_objc_metatype)) {
if (storedRepr)
TC.diagnose(repr->getStartLoc(),
diag::sil_metatype_multiple_reprs);
storedRepr = MetatypeRepresentation::ObjC;
attrs.clearAttribute(TAK_objc_metatype);
}
if (instanceTy->is<ErrorType>()) {
ty = instanceTy;
} else if (auto metatype = dyn_cast<MetatypeTypeRepr>(repr)) {
ty = buildMetatypeType(metatype, instanceTy, storedRepr);
} else {
ty = buildProtocolType(cast<ProtocolTypeRepr>(repr),
instanceTy, storedRepr);
}
}
}
}
}
// Pass down the variable function type attributes to the
// function-type creator.
static const TypeAttrKind FunctionAttrs[] = {
TAK_objc_block, TAK_convention, TAK_thin, TAK_noreturn,
TAK_callee_owned, TAK_callee_guaranteed, TAK_noescape
};
auto checkUnsupportedAttr = [&](TypeAttrKind attr) {
if (attrs.has(attr)) {
TC.diagnose(attrs.getLoc(attr), diag::attribute_not_supported);
attrs.clearAttribute(attr);
}
};
// Some function representation attributes are not supported at source level;
// only SIL knows how to handle them. Reject them unless this is a SIL input.
if (!(options & TR_SILType)) {
for (auto silOnlyAttr : {TAK_callee_owned, TAK_callee_guaranteed}) {
checkUnsupportedAttr(silOnlyAttr);
}
}
// Other function representation attributes are not normally supported at
// source level, but we want to support them there in SIL files.
auto SF = DC->getParentSourceFile();
if (!SF || SF->Kind != SourceFileKind::SIL) {
for (auto silOnlyAttr : {TAK_thin, TAK_thick}) {
checkUnsupportedAttr(silOnlyAttr);
}
}
bool hasFunctionAttr = false;
for (auto i : FunctionAttrs)
if (attrs.has(i)) {
hasFunctionAttr = true;
break;
}
// Function attributes require a syntactic function type.
FunctionTypeRepr *fnRepr = dyn_cast<FunctionTypeRepr>(repr);
if (hasFunctionAttr && fnRepr) {
// Functions cannot be both @thin and @objc_block.
bool thin = attrs.has(TAK_thin);
bool block = attrs.has(TAK_objc_block);
if (thin && block) {
TC.diagnose(attrs.getLoc(TAK_objc_block),
diag::objc_block_cannot_be_thin)
.highlight(attrs.getLoc(TAK_thin));
thin = false;
}
bool isNoEscape = attrs.has(TAK_noescape);
auto calleeConvention = ParameterConvention::Direct_Unowned;
if (attrs.has(TAK_callee_owned)) {
if (attrs.has(TAK_callee_guaranteed)) {
TC.diagnose(attrs.getLoc(TAK_callee_owned),
diag::sil_function_repeat_convention, /*callee*/ 2);
}
calleeConvention = ParameterConvention::Direct_Owned;
} else if (attrs.has(TAK_callee_guaranteed)) {
calleeConvention = ParameterConvention::Direct_Guaranteed;
}
if (options & TR_SILType) {
SILFunctionType::Representation rep;
if (attrs.hasConvention()) {
// SIL exposes a greater number of conventions than Swift source.
auto parsedRep =
llvm::StringSwitch<Optional<SILFunctionType::Representation>>
(attrs.getConvention())
.Case("thick", SILFunctionType::Representation::Thick)
.Case("block", SILFunctionType::Representation::Block)
.Case("thin", SILFunctionType::Representation::Thin)
.Case("c", SILFunctionType::Representation::CFunctionPointer)
.Case("method", SILFunctionType::Representation::Method)
.Case("objc_method", SILFunctionType::Representation::ObjCMethod)
.Case("witness_method", SILFunctionType::Representation::WitnessMethod)
.Default(None);
if (!parsedRep) {
TC.diagnose(attrs.getLoc(TAK_convention),
diag::unsupported_sil_convention, attrs.getConvention());
rep = SILFunctionType::Representation::Thin;
} else {
rep = *parsedRep;
}
// Don't allow both @convention and the old representation attrs.
if (attrs.has(TAK_thin)) {
TC.diagnose(attrs.getLoc(TAK_thin),
diag::convention_with_deprecated_representation_attribute,
"thin");
}
if (attrs.has(TAK_objc_block)) {
TC.diagnose(attrs.getLoc(TAK_objc_block),
diag::convention_with_deprecated_representation_attribute,
"objc_block");
}
} else {
// Error on the old @thin, @cc, and @objc_block attributes in SIL mode.
if (thin) {
TC.diagnose(attrs.getLoc(TAK_thin),
diag::sil_deprecated_convention_attribute,
"thin", "thin");
rep = SILFunctionType::Representation::Block;
} else if (block) {
TC.diagnose(attrs.getLoc(TAK_thin),
diag::sil_deprecated_convention_attribute,
"objc_block", "block");
rep = SILFunctionType::Representation::Block;
} else {
rep = SILFunctionType::Representation::Thick;
}
}
// Resolve the function type directly with these attributes.
SILFunctionType::ExtInfo extInfo(rep,
attrs.has(TAK_noreturn));
ty = resolveSILFunctionType(fnRepr, options, extInfo, calleeConvention);
if (!ty || ty->is<ErrorType>()) return ty;
} else {
FunctionType::Representation rep;
if (attrs.hasConvention()) {
auto parsedRep =
llvm::StringSwitch<Optional<FunctionType::Representation>>
(attrs.getConvention())
.Case("swift", FunctionType::Representation::Swift)
.Case("block", FunctionType::Representation::Block)
.Case("thin", FunctionType::Representation::Thin)
.Case("c", FunctionType::Representation::CFunctionPointer)
.Default(None);
if (!parsedRep) {
TC.diagnose(attrs.getLoc(TAK_convention),
diag::unsupported_convention, attrs.getConvention());
rep = FunctionType::Representation::Swift;
} else {
rep = *parsedRep;
}
// Don't allow both @convention and the old representation attrs.
if (attrs.has(TAK_thin)) {
TC.diagnose(attrs.getLoc(TAK_thin),
diag::convention_with_deprecated_representation_attribute,
"thin");
}
if (attrs.has(TAK_objc_block)) {
TC.diagnose(attrs.getLoc(TAK_objc_block),
diag::convention_with_deprecated_representation_attribute,
"objc_block");
}
} else {
auto fixDeprecatedAttribute = [&](TypeAttrKind kind,
StringRef oldName,
StringRef newName) {
auto start = attrs.getLoc(kind);
SmallString<32> fixitString;
{
llvm::raw_svector_ostream os(fixitString);
os << "convention(" << newName << ")";
}
TC.diagnose(start, diag::deprecated_convention_attribute,
oldName, newName)
.highlight(start)
.fixItReplace(start, fixitString);
};
// Handle the old attributes.
if (thin) {
rep = FunctionType::Representation::Thin;
fixDeprecatedAttribute(TAK_thin, "thin", "thin");
} else if (block) {
rep = FunctionType::Representation::Block;
fixDeprecatedAttribute(TAK_objc_block, "objc_block", "block");
} else {
rep = FunctionType::Representation::Swift;
}
}
// Resolve the function type directly with these attributes.
FunctionType::ExtInfo extInfo(rep,
attrs.has(TAK_noreturn),
/*autoclosure is a decl attr*/false,
isNoEscape,
fnRepr->throws());
ty = resolveASTFunctionType(fnRepr, options, extInfo);
if (!ty || ty->is<ErrorType>()) return ty;
}
for (auto i : FunctionAttrs)
attrs.clearAttribute(i);
attrs.convention = None;
} else if (hasFunctionAttr) {
for (auto i : FunctionAttrs) {
if (attrs.has(i)) {
TC.diagnose(attrs.getLoc(i), diag::attribute_requires_function_type);
attrs.clearAttribute(i);
}
}
}
// If we didn't build the type differently above, build it normally now.
if (!ty) ty = resolveType(repr, options);
if (!ty || ty->is<ErrorType>()) return ty;
// In SIL, handle @opened (n), which creates an existential archetype.
if (attrs.has(TAK_opened)) {
if (!ty->isExistentialType()) {
TC.diagnose(attrs.getLoc(TAK_opened), diag::opened_non_protocol, ty);
} else {
ty = ArchetypeType::getOpened(ty, attrs.OpenedID);
}
attrs.clearAttribute(TAK_opened);
}
// In SIL files *only*, permit @weak and @unowned to apply directly to types.
if (attrs.hasOwnership()) {
if (auto SF = DC->getParentSourceFile()) {
if (SF->Kind == SourceFileKind::SIL) {
if (((attrs.has(TAK_sil_weak) || attrs.has(TAK_sil_unmanaged)) &&
ty->getAnyOptionalObjectType()) ||
(!attrs.has(TAK_sil_weak) && ty->hasReferenceSemantics())) {
ty = ReferenceStorageType::get(ty, attrs.getOwnership(), Context);
attrs.clearOwnership();
}
}
}
}
// In SIL *only*, allow @block_storage to specify a block storage type.
if ((options & TR_SILType) && attrs.has(TAK_block_storage)) {
ty = SILBlockStorageType::get(ty->getCanonicalType());
attrs.clearAttribute(TAK_block_storage);
}
// In SIL *only*, allow @box to specify a box type.
if ((options & TR_SILType) && attrs.has(TAK_box)) {
ty = SILBoxType::get(ty->getCanonicalType());
attrs.clearAttribute(TAK_box);
}
// Diagnose @local_storage in nested positions.
if (attrs.has(TAK_local_storage)) {
assert(DC->getParentSourceFile()->Kind == SourceFileKind::SIL);
TC.diagnose(attrs.getLoc(TAK_local_storage),diag::sil_local_storage_nested);
attrs.clearAttribute(TAK_local_storage);
}
for (unsigned i = 0; i != TypeAttrKind::TAK_Count; ++i)
if (attrs.has((TypeAttrKind)i))
TC.diagnose(attrs.getLoc((TypeAttrKind)i),
diag::attribute_does_not_apply_to_type);
return ty;
}
Type TypeResolver::resolveASTFunctionType(FunctionTypeRepr *repr,
TypeResolutionOptions options,
FunctionType::ExtInfo extInfo) {
Type inputTy = resolveType(repr->getArgsTypeRepr(),
options | TR_ImmediateFunctionInput);
if (!inputTy || inputTy->is<ErrorType>()) return inputTy;
Type outputTy = resolveType(repr->getResultTypeRepr(), options);
if (!outputTy || outputTy->is<ErrorType>()) return outputTy;
extInfo = extInfo.withThrows(repr->throws());
// SIL uses polymorphic function types to resolve overloaded member functions.
if (auto generics = repr->getGenericParams()) {
return PolymorphicFunctionType::get(inputTy, outputTy, generics, extInfo);
}
auto fnTy = FunctionType::get(inputTy, outputTy, extInfo);
// If the type is a block or C function pointer, it must be representable in
// ObjC.
switch (auto rep = extInfo.getRepresentation()) {
case AnyFunctionType::Representation::Block:
case AnyFunctionType::Representation::CFunctionPointer:
if (!TC.isRepresentableInObjC(DC, fnTy)) {
StringRef strName =
rep == AnyFunctionType::Representation::Block ? "block" : "c";
auto extInfo2 =
extInfo.withRepresentation(AnyFunctionType::Representation::Swift);
auto simpleFnTy = FunctionType::get(inputTy, outputTy, extInfo2);
TC.diagnose(repr->getStartLoc(), diag::objc_convention_invalid,
simpleFnTy, strName);
}
break;
case AnyFunctionType::Representation::Thin:
case AnyFunctionType::Representation::Swift:
break;
}
return fnTy;
}
Type TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr,
TypeResolutionOptions options,
SILFunctionType::ExtInfo extInfo,
ParameterConvention callee) {
bool hasError = false;
SmallVector<SILParameterInfo, 4> params;
if (auto tuple = dyn_cast<TupleTypeRepr>(repr->getArgsTypeRepr())) {
// SIL functions cannot be variadic.
if (tuple->hasEllipsis()) {
TC.diagnose(tuple->getEllipsisLoc(), diag::sil_function_ellipsis);
}
for (auto elt : tuple->getElements()) {
if (auto named = dyn_cast<NamedTypeRepr>(elt)) {
TC.diagnose(named->getNameLoc(), diag::sil_function_label);
elt = named->getTypeRepr();
}
auto param = resolveSILParameter(elt,options | TR_ImmediateFunctionInput);
params.push_back(param);
if (!param.getType()) return nullptr;
if (param.getType()->is<ErrorType>())
hasError = true;
}
} else {
SILParameterInfo param = resolveSILParameter(repr->getArgsTypeRepr(),
options | TR_ImmediateFunctionInput);
params.push_back(param);
if (!param.getType()) return nullptr;
if (param.getType()->is<ErrorType>())
hasError = true;
}
SILResultInfo result;
Optional<SILResultInfo> errorResult;
{
// For now, resolveSILResults only returns a single ordinary result.
// FIXME: Deal with unsatisfied dependencies.
SmallVector<SILResultInfo, 1> ordinaryResults;
if (resolveSILResults(repr->getResultTypeRepr(), options,
ordinaryResults, errorResult)) {
hasError = true;
} else {
if (ordinaryResults.empty()) {
result = SILResultInfo(TupleType::getEmpty(TC.Context),
ResultConvention::Unowned);
} else {
result = ordinaryResults.front();
}
}
}
if (hasError) {
return ErrorType::get(Context);
}
// FIXME: Remap the parsed context types to interface types.
GenericSignature *genericSig = nullptr;
SmallVector<SILParameterInfo, 4> interfaceParams;
SILResultInfo interfaceResult;
Optional<SILResultInfo> interfaceErrorResult;
if (repr->getGenericParams()) {
llvm::DenseMap<ArchetypeType*, Type> archetypeMap;
genericSig
= repr->getGenericParams()->getAsCanonicalGenericSignature(archetypeMap,
Context);
auto getArchetypesAsDependentTypes = [&](Type t) -> Type {
if (!t) return t;
if (auto arch = t->getAs<ArchetypeType>()) {
// As a kludge, we allow Self archetypes of protocol_methods to be
// unapplied.
if (arch->getSelfProtocol() && !archetypeMap.count(arch))
return arch;
return arch->getAsDependentType(archetypeMap);
}
return t;
};
for (auto &param : params) {
auto transParamType =
param.getType().transform(getArchetypesAsDependentTypes)
->getCanonicalType();
interfaceParams.push_back(param.getWithType(transParamType));
}
auto transResultType =
result.getType().transform(getArchetypesAsDependentTypes)
->getCanonicalType();
interfaceResult = result.getWithType(transResultType);
if (errorResult) {
auto transErrorResultType =
errorResult->getType().transform(getArchetypesAsDependentTypes)
->getCanonicalType();
interfaceErrorResult =
errorResult->getWithType(transErrorResultType);
}
} else {
interfaceParams = params;
interfaceResult = result;
interfaceErrorResult = errorResult;
}
return SILFunctionType::get(genericSig, extInfo,
callee,
interfaceParams, interfaceResult,
interfaceErrorResult,
Context);
}
SILParameterInfo TypeResolver::resolveSILParameter(
TypeRepr *repr,
TypeResolutionOptions options) {
assert((options & TR_FunctionInput) | (options & TR_ImmediateFunctionInput) &&
"Parameters should be marked as inputs");
auto convention = DefaultParameterConvention;
Type type;
bool hadError = false;
if (auto attrRepr = dyn_cast<AttributedTypeRepr>(repr)) {
auto attrs = attrRepr->getAttrs();
auto checkFor = [&](TypeAttrKind tak, ParameterConvention attrConv) {
if (!attrs.has(tak)) return;
if (convention != DefaultParameterConvention) {
TC.diagnose(attrs.getLoc(tak), diag::sil_function_repeat_convention,
/*input*/ 0);
hadError = true;
}
attrs.clearAttribute(tak);
convention = attrConv;
};
checkFor(TypeAttrKind::TAK_in_guaranteed,
ParameterConvention::Indirect_In_Guaranteed);
checkFor(TypeAttrKind::TAK_in, ParameterConvention::Indirect_In);
checkFor(TypeAttrKind::TAK_out, ParameterConvention::Indirect_Out);
checkFor(TypeAttrKind::TAK_inout, ParameterConvention::Indirect_Inout);
checkFor(TypeAttrKind::TAK_inout_aliasable,
ParameterConvention::Indirect_InoutAliasable);
checkFor(TypeAttrKind::TAK_owned, ParameterConvention::Direct_Owned);
checkFor(TypeAttrKind::TAK_guaranteed,
ParameterConvention::Direct_Guaranteed);
checkFor(TypeAttrKind::TAK_deallocating,
ParameterConvention::Direct_Deallocating);
type = resolveAttributedType(attrs, attrRepr->getTypeRepr(), options);
} else {
type = resolveType(repr, options);
}
if (!type) return SILParameterInfo(CanType(), convention);
if (hadError) type = ErrorType::get(Context);
return SILParameterInfo(type->getCanonicalType(), convention);
}
bool TypeResolver::resolveSingleSILResult(TypeRepr *repr,
TypeResolutionOptions options,
SmallVectorImpl<SILResultInfo> &ordinaryResults,
Optional<SILResultInfo> &errorResult) {
Type type;
auto convention = DefaultResultConvention;
bool isErrorResult = false;
if (auto attrRepr = dyn_cast<AttributedTypeRepr>(repr)) {
// Copy the attributes out; we're going to destructively modify them.
auto attrs = attrRepr->getAttrs();
// Recognize @error.
if (attrs.has(TypeAttrKind::TAK_error)) {
attrs.clearAttribute(TypeAttrKind::TAK_error);
isErrorResult = true;
// Error results are always implicitly @owned.
convention = ResultConvention::Owned;
}
// Recognize result conventions.
bool hadError = false;
auto checkFor = [&](TypeAttrKind tak, ResultConvention attrConv) {
if (!attrs.has(tak)) return;
if (convention != DefaultResultConvention) {
TC.diagnose(attrs.getLoc(tak), diag::sil_function_repeat_convention,
/*result*/ 1);
hadError = true;
}
attrs.clearAttribute(tak);
convention = attrConv;
};
checkFor(TypeAttrKind::TAK_owned, ResultConvention::Owned);
checkFor(TypeAttrKind::TAK_unowned_inner_pointer,
ResultConvention::UnownedInnerPointer);
checkFor(TypeAttrKind::TAK_autoreleased, ResultConvention::Autoreleased);
if (hadError) return true;
type = resolveAttributedType(attrs, attrRepr->getTypeRepr(), options);
} else {
type = resolveType(repr, options);
}
// Propagate type-resolution errors out.
if (!type || type->is<ErrorType>()) return true;
assert(!isErrorResult || convention == ResultConvention::Owned);
SILResultInfo resolvedResult(type->getCanonicalType(), convention);
// TODO: we want to generalize this to allow multiple normal results.
// But for now, just allow one.
if (!isErrorResult) {
if (!ordinaryResults.empty()) {
TC.diagnose(repr->getStartLoc(), diag::sil_function_multiple_results);
return true;
}
ordinaryResults.push_back(resolvedResult);
return false;
}
// Error result types must have pointer-like representation.
// FIXME: check that here?
// We don't expect to have a reason to support multiple independent
// error results. (Would this be disjunctive or conjunctive?)
if (errorResult.hasValue()) {
TC.diagnose(repr->getStartLoc(),
diag::sil_function_multiple_error_results);
return true;
}
errorResult = resolvedResult;
return false;
}
static bool hasElementWithSILResultAttribute(TupleTypeRepr *tuple) {
for (auto elt : tuple->getElements()) {
if (auto attrRepr = dyn_cast<AttributedTypeRepr>(elt)) {
const TypeAttributes &attrs = attrRepr->getAttrs();
if (attrs.has(TypeAttrKind::TAK_owned) ||
attrs.has(TypeAttrKind::TAK_unowned_inner_pointer) ||
attrs.has(TypeAttrKind::TAK_autoreleased) ||
attrs.has(TypeAttrKind::TAK_error)) {
return true;
}
}
}
return false;
}
bool TypeResolver::resolveSILResults(TypeRepr *repr,
TypeResolutionOptions options,
SmallVectorImpl<SILResultInfo> &ordinaryResults,
Optional<SILResultInfo> &errorResult) {
// When we generalize SIL to handle multiple normal results, we
// should always split up a tuple (a single level deep only). Until
// then, we need to recognize when the tuple elements don't use any
// SIL result attributes and keep it as a single result.
if (auto tuple = dyn_cast<TupleTypeRepr>(repr)) {
if (hasElementWithSILResultAttribute(tuple)) {
bool hadError = false;
for (auto elt : tuple->getElements()) {
if (resolveSingleSILResult(elt, options, ordinaryResults, errorResult))
hadError = true;
}
return hadError;
}
}
return resolveSingleSILResult(repr, options, ordinaryResults, errorResult);
}
Type TypeResolver::resolveInOutType(InOutTypeRepr *repr,
TypeResolutionOptions options) {
Type ty = resolveType(cast<InOutTypeRepr>(repr)->getBase(), options);
if (!ty || ty->is<ErrorType>()) return ty;
if (!(options & TR_FunctionInput) &&
!(options & TR_ImmediateFunctionInput)) {
TC.diagnose(repr->getInOutLoc(), diag::inout_only_parameter);
repr->setInvalid();
return ErrorType::get(Context);
}
return InOutType::get(ty);
}
Type TypeResolver::resolveArrayType(ArrayTypeRepr *repr,
TypeResolutionOptions options) {
// FIXME: diagnose non-materializability of element type!
Type baseTy = resolveType(repr->getBase(), withoutContext(options));
if (!baseTy || baseTy->is<ErrorType>()) return baseTy;
auto sliceTy = TC.getArraySliceType(repr->getBrackets().Start, baseTy);
if (!sliceTy)
return ErrorType::get(Context);
return sliceTy;
}
Type TypeResolver::resolveDictionaryType(DictionaryTypeRepr *repr,
TypeResolutionOptions options) {
// FIXME: diagnose non-materializability of key/value type?
Type keyTy = resolveType(repr->getKey(), withoutContext(options));
if (!keyTy || keyTy->is<ErrorType>()) return keyTy;
Type valueTy = resolveType(repr->getValue(), withoutContext(options));
if (!valueTy || valueTy->is<ErrorType>()) return valueTy;
if (auto dictTy = TC.getDictionaryType(repr->getBrackets().Start, keyTy,
valueTy)) {
// Check the requirements on the generic arguments.
auto unboundTy = UnboundGenericType::get(TC.Context.getDictionaryDecl(),
nullptr, TC.Context);
TypeLoc args[2] = { TypeLoc(repr->getKey()), TypeLoc(repr->getValue()) };
if (!TC.applyGenericArguments(unboundTy, repr->getStartLoc(), DC, args,
options.contains(TR_GenericSignature),
Resolver)) {
return ErrorType::get(TC.Context);
}
return dictTy;
}
return ErrorType::get(Context);
}
Type TypeResolver::resolveOptionalType(OptionalTypeRepr *repr,
TypeResolutionOptions options) {
// The T in T? is a generic type argument and therefore always an AST type.
// FIXME: diagnose non-materializability of element type!
Type baseTy = resolveType(repr->getBase(), withoutContext(options));
if (!baseTy || baseTy->is<ErrorType>()) return baseTy;
auto optionalTy = TC.getOptionalType(repr->getQuestionLoc(), baseTy);
if (!optionalTy) return ErrorType::get(Context);
return optionalTy;
}
Type TypeResolver::resolveImplicitlyUnwrappedOptionalType(
ImplicitlyUnwrappedOptionalTypeRepr *repr,
TypeResolutionOptions options) {
// The T in T! is a generic type argument and therefore always an AST type.
// FIXME: diagnose non-materializability of element type!
Type baseTy = resolveType(repr->getBase(), withoutContext(options));
if (!baseTy || baseTy->is<ErrorType>()) return baseTy;
auto uncheckedOptionalTy =
TC.getImplicitlyUnwrappedOptionalType(repr->getExclamationLoc(), baseTy);
if (!uncheckedOptionalTy)
return ErrorType::get(Context);
return uncheckedOptionalTy;
}
Type TypeResolver::resolveTupleType(TupleTypeRepr *repr,
TypeResolutionOptions options) {
SmallVector<TupleTypeElt, 8> elements;
elements.reserve(repr->getElements().size());
// If this is the top level of a function input list, peel off the
// ImmediateFunctionInput marker and install a FunctionInput one instead.
auto elementOptions = withoutContext(options);
if (options & TR_ImmediateFunctionInput)
elementOptions |= TR_FunctionInput;
for (auto tyR : repr->getElements()) {
if (NamedTypeRepr *namedTyR = dyn_cast<NamedTypeRepr>(tyR)) {
Type ty = resolveType(namedTyR->getTypeRepr(), elementOptions);
if (!ty || ty->is<ErrorType>()) return ty;
elements.push_back(TupleTypeElt(ty, namedTyR->getName()));
} else {
Type ty = resolveType(tyR, elementOptions);
if (!ty || ty->is<ErrorType>()) return ty;
elements.push_back(TupleTypeElt(ty));
}
}
// Tuple representations are limited outside of function inputs.
if (!(options & TR_ImmediateFunctionInput)) {
bool complained = false;
// Variadic tuples are not permitted.
if (repr->hasEllipsis()) {
TC.diagnose(repr->getEllipsisLoc(), diag::tuple_ellipsis);
repr->removeEllipsis();
complained = true;
}
// Single-element labeled tuples are not permitted, either.
if (elements.size() == 1 && elements[0].hasName() &&
!(options & TR_EnumCase)) {
if (!complained) {
auto named = cast<NamedTypeRepr>(repr->getElement(0));
TC.diagnose(repr->getElement(0)->getStartLoc(),
diag::tuple_single_element)
.fixItRemoveChars(named->getStartLoc(),
named->getTypeRepr()->getStartLoc());
}
elements[0] = TupleTypeElt(elements[0].getType());
}
}
if (repr->hasEllipsis()) {
auto &element = elements[repr->getEllipsisIndex()];
Type baseTy = element.getType();
Type fullTy = TC.getArraySliceType(repr->getEllipsisLoc(), baseTy);
Identifier name = element.getName();
element = TupleTypeElt(fullTy, name, DefaultArgumentKind::None, true);
}
return TupleType::get(elements, Context);
}
Type TypeResolver::resolveProtocolCompositionType(
ProtocolCompositionTypeRepr *repr,
TypeResolutionOptions options) {
SmallVector<Type, 4> ProtocolTypes;
for (auto tyR : repr->getProtocols()) {
Type ty = TC.resolveType(tyR, DC, withoutContext(options), Resolver);
if (!ty || ty->is<ErrorType>()) return ty;
if (!ty->isExistentialType()) {
TC.diagnose(tyR->getStartLoc(), diag::protocol_composition_not_protocol,
ty);
continue;
}
ProtocolTypes.push_back(ty);
}
return ProtocolCompositionType::get(Context, ProtocolTypes);
}
Type TypeResolver::resolveMetatypeType(MetatypeTypeRepr *repr,
TypeResolutionOptions options) {
// The instance type of a metatype is always abstract, not SIL-lowered.
Type ty = resolveType(repr->getBase(), withoutContext(options));
if (!ty || ty->is<ErrorType>()) return ty;
Optional<MetatypeRepresentation> storedRepr;
// In SIL mode, a metatype must have a @thin, @thick, or
// @objc_metatype attribute, so metatypes should have been lowered
// in resolveAttributedType.
if (options & TR_SILType) {
TC.diagnose(repr->getStartLoc(), diag::sil_metatype_without_repr);
storedRepr = MetatypeRepresentation::Thick;
}
return buildMetatypeType(repr, ty, storedRepr);
}
Type TypeResolver::buildMetatypeType(
MetatypeTypeRepr *repr,
Type instanceType,
Optional<MetatypeRepresentation> storedRepr) {
if (instanceType->isAnyExistentialType()) {
// TODO: diagnose invalid representations?
return ExistentialMetatypeType::get(instanceType, storedRepr);
} else {
return MetatypeType::get(instanceType, storedRepr);
}
}
Type TypeResolver::resolveProtocolType(ProtocolTypeRepr *repr,
TypeResolutionOptions options) {
// The instance type of a metatype is always abstract, not SIL-lowered.
Type ty = resolveType(repr->getBase(), withoutContext(options));
if (!ty || ty->is<ErrorType>()) return ty;
Optional<MetatypeRepresentation> storedRepr;
// In SIL mode, a metatype must have a @thin, @thick, or
// @objc_metatype attribute, so metatypes should have been lowered
// in resolveAttributedType.
if (options & TR_SILType) {
TC.diagnose(repr->getStartLoc(), diag::sil_metatype_without_repr);
storedRepr = MetatypeRepresentation::Thick;
}
return buildProtocolType(repr, ty, storedRepr);
}
Type TypeResolver::buildProtocolType(
ProtocolTypeRepr *repr,
Type instanceType,
Optional<MetatypeRepresentation> storedRepr) {
if (!instanceType->isAnyExistentialType()) {
TC.diagnose(repr->getProtocolLoc(), diag::dot_protocol_on_non_existential,
instanceType);
return ErrorType::get(TC.Context);
}
return MetatypeType::get(instanceType, storedRepr);
}
Type TypeChecker::substMemberTypeWithBase(Module *module,
const ValueDecl *member,
Type baseTy, bool isTypeReference) {
Type memberType = isTypeReference
? cast<TypeDecl>(member)->getDeclaredInterfaceType()
: member->getInterfaceType();
if (isTypeReference) {
// The declared interface type for a generic type will have the type
// arguments; strip them off.
if (auto nominalTypeDecl = dyn_cast<NominalTypeDecl>(member)) {
if (auto boundGenericTy = memberType->getAs<BoundGenericType>()) {
memberType = UnboundGenericType::get(
const_cast<NominalTypeDecl *>(nominalTypeDecl),
boundGenericTy->getParent(),
Context);
}
}
}
return baseTy->getTypeOfMember(module, member, this, memberType);
}
Type TypeChecker::getSuperClassOf(Type type) {
return type->getSuperclass(this);
}
Type TypeChecker::resolveMemberType(DeclContext *dc, Type type,
Identifier name) {
LookupTypeResult memberTypes = lookupMemberType(dc, type, name);
if (!memberTypes)
return Type();
// FIXME: Detect ambiguities here?
return memberTypes.back().second;
}
/// Look up and validate a type declared in the standard library.
static CanType lookupUniqueTypeInLibrary(TypeChecker &TC,
Module *stdlib,
Identifier name) {
SmallVector<ValueDecl *, 4> results;
stdlib->lookupValue({}, name, NLKind::UnqualifiedLookup, results);
TypeDecl *type = nullptr;
for (auto result: results) {
if (auto foundType = dyn_cast<TypeDecl>(result)) {
// Fail if we find two types with this name.
if (type) return CanType();
type = foundType;
}
}
// Fail if we didn't find a type.
if (!type) return CanType();
TC.validateDecl(type);
if (type->isInvalid()) return CanType();
return type->getDeclaredType()->getCanonicalType();
}
static void lookupAndAddLibraryTypes(TypeChecker &TC,
Module *Stdlib,
ArrayRef<Identifier> TypeNames,
llvm::DenseSet<CanType> &Types) {
SmallVector<ValueDecl *, 4> Results;
for (Identifier Id : TypeNames) {
Stdlib->lookupValue({}, Id, NLKind::UnqualifiedLookup, Results);
for (auto *VD : Results) {
if (auto *TD = dyn_cast<TypeDecl>(VD)) {
TC.validateDecl(TD);
Types.insert(TD->getDeclaredType()->getCanonicalType());
}
}
Results.clear();
}
}
/// Emit an additional diagnostic describing why we are applying @objc to the
/// decl, if this is not obvious from the decl itself.
static void describeObjCReason(TypeChecker &TC, const ValueDecl *VD,
ObjCReason Reason) {
if (Reason == ObjCReason::MemberOfObjCProtocol) {
TC.diagnose(VD->getLoc(), diag::objc_inferring_on_objc_protocol_member);
} else if (Reason == ObjCReason::OverridesObjC) {
unsigned kind = isa<VarDecl>(VD) ? 0
: isa<SubscriptDecl>(VD) ? 1
: isa<ConstructorDecl>(VD) ? 2
: 3;
auto overridden = VD->getOverriddenDecl();
if (overridden->getLoc().isValid()) {
TC.diagnose(overridden->getLoc(), diag::objc_overriding_objc_decl,
kind, VD->getOverriddenDecl()->getFullName());
}
}
}
static void diagnoseFunctionParamNotRepresentable(
TypeChecker &TC, const AbstractFunctionDecl *AFD, unsigned NumParams,
unsigned ParamIndex, const ParamDecl *P, ObjCReason Reason) {
if (Reason == ObjCReason::DoNotDiagnose)
return;
if (NumParams == 1) {
TC.diagnose(AFD->getLoc(), diag::objc_invalid_on_func_single_param_type,
getObjCDiagnosticAttrKind(Reason));
} else {
TC.diagnose(AFD->getLoc(), diag::objc_invalid_on_func_param_type,
ParamIndex + 1, getObjCDiagnosticAttrKind(Reason));
}
if (P->hasType()) {
Type ParamTy = P->getType();
SourceRange SR;
if (auto typeRepr = P->getTypeLoc().getTypeRepr())
SR = typeRepr->getSourceRange();
TC.diagnoseTypeNotRepresentableInObjC(AFD, ParamTy, SR);
}
describeObjCReason(TC, AFD, Reason);
}
static bool isParamListRepresentableInObjC(TypeChecker &TC,
const AbstractFunctionDecl *AFD,
const ParameterList *PL,
ObjCReason Reason) {
// If you change this function, you must add or modify a test in PrintAsObjC.
bool Diagnose = (Reason != ObjCReason::DoNotDiagnose);
bool IsObjC = true;
unsigned NumParams = PL->size();
for (unsigned ParamIndex = 0; ParamIndex != NumParams; ParamIndex++) {
auto param = PL->get(ParamIndex);
// Swift Varargs are not representable in Objective-C.
if (param->isVariadic()) {
if (Diagnose && Reason != ObjCReason::DoNotDiagnose) {
TC.diagnose(param->getStartLoc(), diag::objc_invalid_on_func_variadic,
getObjCDiagnosticAttrKind(Reason))
.highlight(param->getSourceRange());
describeObjCReason(TC, AFD, Reason);
}
return false;
}
if (TC.isRepresentableInObjC(AFD, param->getType()))
continue;
// Permit '()' when this method overrides a method with a
// foreign error convention that replaces NSErrorPointer with ()
// and this is the replaced parameter.
AbstractFunctionDecl *overridden;
if (param->getType()->isVoid() && AFD->isBodyThrowing() &&
(overridden = AFD->getOverriddenDecl())) {
auto foreignError = overridden->getForeignErrorConvention();
if (foreignError &&
foreignError->isErrorParameterReplacedWithVoid() &&
foreignError->getErrorParameterIndex() == ParamIndex) {
continue;
}
}
IsObjC = false;
if (!Diagnose) {
// Save some work and return as soon as possible if we are not
// producing diagnostics.
return IsObjC;
}
diagnoseFunctionParamNotRepresentable(TC, AFD, NumParams, ParamIndex,
param, Reason);
}
return IsObjC;
}
/// Check whether the given declaration occurs within a constrained
/// extension, or an extension of a class with generic ancestry, and
/// therefore is not representable in Objective-C.
static bool checkObjCInExtensionContext(TypeChecker &tc,
const ValueDecl *value,
bool diagnose) {
auto DC = value->getDeclContext();
if (auto ED = dyn_cast<ExtensionDecl>(DC)) {
if (ED->getTrailingWhereClause()) {
if (diagnose) {
tc.diagnose(value->getLoc(), diag::objc_in_extension_context);
}
return true;
}
// Check if any classes in the inheritance hierarchy have generic
// parameters.
// FIXME: This is a current limitation, not inherent. We don't have
// a concrete class to attach Objective-C category metadata to.
Type extendedTy = ED->getDeclaredTypeInContext();
while (!extendedTy.isNull()) {
const ClassDecl *CD = extendedTy->getClassOrBoundGenericClass();
if (!CD)
break;
if (CD->getGenericParams()) {
if (diagnose) {
tc.diagnose(value->getLoc(), diag::objc_in_generic_extension);
}
return true;
}
extendedTy = CD->getSuperclass();
}
}
return false;
}
/// Check whether the given declaration contains its own generic parameters,
/// and therefore is not representable in Objective-C.
static bool checkObjCWithGenericParams(TypeChecker &TC,
const AbstractFunctionDecl *AFD,
ObjCReason Reason) {
bool Diagnose = (Reason != ObjCReason::DoNotDiagnose);
if (AFD->getGenericParams()) {
// Diagnose this problem, if asked to.
if (Diagnose) {
TC.diagnose(AFD->getLoc(), diag::objc_invalid_with_generic_params,
getObjCDiagnosticAttrKind(Reason));
describeObjCReason(TC, AFD, Reason);
}
return true;
}
return false;
}
static bool isForeignClassContext(DeclContext *DC) {
auto type = DC->getDeclaredTypeInContext();
if (!type)
return false;
auto clas = type->getClassOrBoundGenericClass();
if (!clas)
return false;
return clas->isForeign();
}
/// CF types cannot have @objc methods, because they don't have real class
/// objects.
static bool checkObjCInForeignClassContext(TypeChecker &TC,
const ValueDecl *VD,
ObjCReason Reason) {
bool Diagnose = (Reason != ObjCReason::DoNotDiagnose);
if (isForeignClassContext(VD->getDeclContext())) {
if (Diagnose) {
TC.diagnose(VD->getLoc(), diag::objc_invalid_on_foreign_class,
getObjCDiagnosticAttrKind(Reason));
describeObjCReason(TC, VD, Reason);
}
return true;
}
return false;
}
bool TypeChecker::isCIntegerType(const DeclContext *DC, Type T) {
if (CIntegerTypes.empty())
fillObjCRepresentableTypeCache(DC);
return CIntegerTypes.count(T->getCanonicalType());
}
/// Determines whether the given type is bridged to an Objective-C class type.
static bool isBridgedToObjectiveCClass(DeclContext *dc, Type type) {
// Simple case: bridgeable object types.
if (type->isBridgeableObjectType())
return true;
// Determine whether this type is bridged to Objective-C.
ASTContext &ctx = type->getASTContext();
Optional<Type> bridged = ctx.getBridgedToObjC(dc, type,
ctx.getLazyResolver());
if (!bridged)
return false;
// Check whether we're bridging to a class.
auto classDecl = (*bridged)->getClassOrBoundGenericClass();
if (!classDecl)
return false;
// Allow anything that isn't bridged to NSNumber.
// FIXME: This feels like a hack, but we don't have the right predicate
// anywhere.
return classDecl->getName().str() != "NSNumber";
}
bool TypeChecker::isRepresentableInObjC(
const AbstractFunctionDecl *AFD,
ObjCReason Reason,
Optional<ForeignErrorConvention> &errorConvention) {
// Clear out the error convention. It will be added later if needed.
errorConvention = None;
// If you change this function, you must add or modify a test in PrintAsObjC.
bool Diagnose = (Reason != ObjCReason::DoNotDiagnose);
if (checkObjCInForeignClassContext(*this, AFD, Reason))
return false;
if (checkObjCWithGenericParams(*this, AFD, Reason))
return false;
if (checkObjCInExtensionContext(*this, AFD, Diagnose))
return false;
if (auto *FD = dyn_cast<FuncDecl>(AFD)) {
if (FD->isAccessor()) {
// Accessors can only be @objc if the storage declaration is.
auto storage = FD->getAccessorStorageDecl();
validateDecl(storage);
if (!storage->isObjC()) {
if (Diagnose) {
auto error = FD->isGetter()
? (isa<VarDecl>(storage)
? diag::objc_getter_for_nonobjc_property
: diag::objc_getter_for_nonobjc_subscript)
: (isa<VarDecl>(storage)
? diag::objc_setter_for_nonobjc_property
: diag::objc_setter_for_nonobjc_subscript);
diagnose(FD->getLoc(), error);
describeObjCReason(*this, AFD, Reason);
}
return false;
}
} else {
unsigned ExpectedParamPatterns = 1;
if (FD->getImplicitSelfDecl())
ExpectedParamPatterns++;
if (FD->getParameterLists().size() != ExpectedParamPatterns) {
if (Diagnose) {
diagnose(AFD->getLoc(), diag::objc_invalid_on_func_curried,
getObjCDiagnosticAttrKind(Reason));
describeObjCReason(*this, AFD, Reason);
}
return false;
}
}
// willSet/didSet implementations are never exposed to objc, they are always
// directly dispatched from the synthesized setter.
if (FD->isObservingAccessor()) {
if (Diagnose) {
diagnose(AFD->getLoc(), diag::objc_observing_accessor);
describeObjCReason(*this, AFD, Reason);
}
return false;
}
}
// As a special case, an initializer with a single, named parameter of type
// '()' is always representable in Objective-C. This allows us to cope with
// zero-parameter methods with selectors that are longer than "init". For
// example, this allows:
//
// \code
// class Foo {
// @objc init(malice: ()) { } // selector is "initWithMalice"
// }
// \endcode
bool isSpecialInit = false;
if (auto init = dyn_cast<ConstructorDecl>(AFD))
isSpecialInit = init->isObjCZeroParameterWithLongSelector();
if (!isSpecialInit &&
!isParamListRepresentableInObjC(*this, AFD, AFD->getParameterList(1),
Reason)) {
if (!Diagnose) {
// Return as soon as possible if we are not producing diagnostics.
return false;
}
}
if (auto FD = dyn_cast<FuncDecl>(AFD)) {
Type ResultType = FD->getResultType();
if (!ResultType->isVoid() && !isRepresentableInObjC(FD, ResultType)) {
if (Diagnose) {
diagnose(AFD->getLoc(), diag::objc_invalid_on_func_result_type,
getObjCDiagnosticAttrKind(Reason));
SourceRange Range =
FD->getBodyResultTypeLoc().getTypeRepr()->getSourceRange();
diagnoseTypeNotRepresentableInObjC(FD, ResultType, Range);
describeObjCReason(*this, FD, Reason);
}
return false;
}
}
// Throwing functions must map to a particular error convention.
if (AFD->isBodyThrowing()) {
DeclContext *dc = const_cast<AbstractFunctionDecl *>(AFD);
SourceLoc throwsLoc;
Type resultType;
const ConstructorDecl *ctor = nullptr;
if (auto func = dyn_cast<FuncDecl>(AFD)) {
resultType = func->getResultType();
throwsLoc = func->getThrowsLoc();
} else {
ctor = cast<ConstructorDecl>(AFD);
throwsLoc = ctor->getThrowsLoc();
}
ForeignErrorConvention::Kind kind;
CanType errorResultType;
Type optOptionalType;
if (ctor) {
// Initializers always use the nil result convention.
kind = ForeignErrorConvention::NilResult;
// Only non-failing initializers can throw.
if (ctor->getFailability() != OTK_None) {
if (Diagnose) {
diagnose(AFD->getLoc(), diag::objc_invalid_on_failing_init,
getObjCDiagnosticAttrKind(Reason))
.highlight(throwsLoc);
describeObjCReason(*this, AFD, Reason);
}
return false;
}
} else if (resultType->isVoid()) {
// Functions that return nothing (void) can be throwing; they indicate
// failure with a 'false' result.
kind = ForeignErrorConvention::ZeroResult;
errorResultType = Context.getBoolDecl()
->getDeclaredInterfaceType()->getCanonicalType();
} else if (!resultType->getAnyOptionalObjectType() &&
isBridgedToObjectiveCClass(dc, resultType)) {
// Functions that return a (non-optional) type bridged to Objective-C
// can be throwing; they indicate failure with a nil result.
kind = ForeignErrorConvention::NilResult;
} else if ((optOptionalType = resultType->getAnyOptionalObjectType()) &&
isBridgedToObjectiveCClass(dc, optOptionalType)) {
// Cannot return an optional bridged type, because 'nil' is reserved
// to indicate failure. Call this out in a separate diagnostic.
if (Diagnose) {
diagnose(AFD->getLoc(),
diag::objc_invalid_on_throwing_optional_result,
getObjCDiagnosticAttrKind(Reason),
resultType)
.highlight(throwsLoc);
describeObjCReason(*this, AFD, Reason);
}
return false;
} else {
// Other result types are not permitted.
if (Diagnose) {
diagnose(AFD->getLoc(),
diag::objc_invalid_on_throwing_result,
getObjCDiagnosticAttrKind(Reason),
resultType)
.highlight(throwsLoc);
describeObjCReason(*this, AFD, Reason);
}
return false;
}
// The error type is always AutoreleasingUnsafeMutablePointer<NSError?>.
Type errorParameterType = getNSErrorType(dc);
if (errorParameterType) {
errorParameterType = OptionalType::get(errorParameterType);
errorParameterType
= BoundGenericType::get(
Context.getAutoreleasingUnsafeMutablePointerDecl(),
nullptr,
errorParameterType);
}
// Determine the parameter index at which the error will go.
unsigned errorParameterIndex;
bool foundErrorParameterIndex = false;
// If there is an explicit @objc attribute with a name, look for
// the "error" selector piece.
if (auto objc = AFD->getAttrs().getAttribute<ObjCAttr>()) {
if (auto objcName = objc->getName()) {
auto selectorPieces = objcName->getSelectorPieces();
for (unsigned i = selectorPieces.size(); i > 0; --i) {
// If the selector piece is "error", this is the location of
// the error parameter.
auto piece = selectorPieces[i-1];
if (piece == Context.Id_error) {
errorParameterIndex = i-1;
foundErrorParameterIndex = true;
break;
}
// If the first selector piece ends with "Error", it's here.
if (i == 1 && camel_case::getLastWord(piece.str()) == "Error") {
errorParameterIndex = i-1;
foundErrorParameterIndex = true;
break;
}
}
}
}
// If the selector did not provide an index for the error, find
// the last parameter that is not a trailing closure.
if (!foundErrorParameterIndex) {
auto *paramList = AFD->getParameterList(1);
errorParameterIndex = paramList->size();
while (errorParameterIndex > 0) {
// Skip over trailing closures.
auto type = paramList->get(errorParameterIndex - 1)->getType();
// It can't be a trailing closure unless it has a specific form.
// Only consider the rvalue type.
type = type->getRValueType();
// Look through one level of optionality.
if (auto objectType = type->getAnyOptionalObjectType())
type = objectType;
// Is it a function type?
if (!type->is<AnyFunctionType>()) break;
--errorParameterIndex;
}
}
// Form the error convention.
CanType canErrorParameterType;
if (errorParameterType)
canErrorParameterType = errorParameterType->getCanonicalType();
switch (kind) {
case ForeignErrorConvention::ZeroResult:
errorConvention = ForeignErrorConvention::getZeroResult(
errorParameterIndex,
ForeignErrorConvention::IsNotOwned,
ForeignErrorConvention::IsNotReplaced,
canErrorParameterType,
errorResultType);
break;
case ForeignErrorConvention::NonZeroResult:
errorConvention = ForeignErrorConvention::getNonZeroResult(
errorParameterIndex,
ForeignErrorConvention::IsNotOwned,
ForeignErrorConvention::IsNotReplaced,
canErrorParameterType,
errorResultType);
break;
case ForeignErrorConvention::ZeroPreservedResult:
errorConvention = ForeignErrorConvention::getZeroPreservedResult(
errorParameterIndex,
ForeignErrorConvention::IsNotOwned,
ForeignErrorConvention::IsNotReplaced,
canErrorParameterType);
break;
case ForeignErrorConvention::NilResult:
errorConvention = ForeignErrorConvention::getNilResult(
errorParameterIndex,
ForeignErrorConvention::IsNotOwned,
ForeignErrorConvention::IsNotReplaced,
canErrorParameterType);
break;
case ForeignErrorConvention::NonNilError:
errorConvention = ForeignErrorConvention::getNilResult(
errorParameterIndex,
ForeignErrorConvention::IsNotOwned,
ForeignErrorConvention::IsNotReplaced,
canErrorParameterType);
break;
}
}
return true;
}
bool TypeChecker::isRepresentableInObjC(const VarDecl *VD, ObjCReason Reason) {
// If you change this function, you must add or modify a test in PrintAsObjC.
if (VD->isInvalid())
return false;
Type T = VD->getType();
if (auto *RST = T->getAs<ReferenceStorageType>()) {
// In-memory layout of @weak and @unowned does not correspond to anything
// in Objective-C, but this does not really matter here, since Objective-C
// uses getters and setters to operate on the property.
// Because of this, look through @weak and @unowned.
T = RST->getReferentType();
}
bool Result = isRepresentableInObjC(VD->getDeclContext(), T);
bool Diagnose = (Reason != ObjCReason::DoNotDiagnose);
if (Result && checkObjCInExtensionContext(*this, VD, Diagnose))
return false;
if (checkObjCInForeignClassContext(*this, VD, Reason))
return false;
if (!Diagnose || Result)
return Result;
SourceRange TypeRange = VD->getTypeSourceRangeForDiagnostics();
diagnose(VD->getLoc(), diag::objc_invalid_on_var,
getObjCDiagnosticAttrKind(Reason))
.highlight(TypeRange);
diagnoseTypeNotRepresentableInObjC(VD->getDeclContext(), VD->getType(),
TypeRange);
describeObjCReason(*this, VD, Reason);
return Result;
}
bool TypeChecker::isRepresentableInObjC(const SubscriptDecl *SD,
ObjCReason Reason) {
// If you change this function, you must add or modify a test in PrintAsObjC.
bool Diagnose = (Reason != ObjCReason::DoNotDiagnose);
if (checkObjCInForeignClassContext(*this, SD, Reason))
return false;
// Figure out the type of the indices.
Type IndicesType = SD->getIndicesType();
if (auto TupleTy = IndicesType->getAs<TupleType>()) {
if (TupleTy->getNumElements() == 1 && !TupleTy->getElement(0).isVararg())
IndicesType = TupleTy->getElementType(0);
}
if (IndicesType->is<ErrorType>())
return false;
bool IndicesResult = isRepresentableInObjC(SD->getDeclContext(), IndicesType);
bool ElementResult = isRepresentableInObjC(SD->getDeclContext(),
SD->getElementType());
bool Result = IndicesResult && ElementResult;
if (Result && checkObjCInExtensionContext(*this, SD, Diagnose))
return false;
// Make sure we know how to map the selector appropriately.
if (Result && SD->getObjCSubscriptKind(this) == ObjCSubscriptKind::None) {
SourceRange IndexRange = SD->getIndices()->getSourceRange();
diagnose(SD->getLoc(), diag::objc_invalid_subscript_key_type,
getObjCDiagnosticAttrKind(Reason), IndicesType)
.highlight(IndexRange);
return false;
}
if (!Diagnose || Result)
return Result;
SourceRange TypeRange;
if (!IndicesResult)
TypeRange = SD->getIndices()->getSourceRange();
else
TypeRange = SD->getElementTypeLoc().getSourceRange();
diagnose(SD->getLoc(), diag::objc_invalid_on_subscript,
getObjCDiagnosticAttrKind(Reason))
.highlight(TypeRange);
diagnoseTypeNotRepresentableInObjC(SD->getDeclContext(),
!IndicesResult? IndicesType
: SD->getElementType(),
TypeRange);
describeObjCReason(*this, SD, Reason);
return Result;
}
/// True if T is representable as a non-nullable ObjC pointer type.
static bool isAnyObjCRepresentableObjectType(Type T) {
// Look through a single level of metatype.
if (auto MTT = T->getAs<AnyMetatypeType>())
T = MTT->getInstanceType();
if (auto dynSelf = T->getAs<DynamicSelfType>())
T = dynSelf->getSelfType();
if (auto *CT = T->getAs<ClassType>())
return CT->getDecl()->isObjC();
return T->isObjCExistentialType();
}
/// True if T is representable as an ObjC pointer type, nullable or otherwise.
static bool isNullableObjCRepresentableObjectType(Type T) {
// Look through a single layer of optional type.
if (auto valueType = T->getAnyOptionalObjectType()) {
T = valueType;
}
return isAnyObjCRepresentableObjectType(T);
}
bool TypeChecker::isTriviallyRepresentableInObjC(const DeclContext *DC,
Type T) {
// If you change this function, you must add or modify a test in PrintAsObjC.
// Look through one level of optional type, but remember that we did.
bool wasOptional = false;
if (auto valueType = T->getAnyOptionalObjectType()) {
T = valueType;
wasOptional = true;
}
// T can be represented in Objective-C if T is an @objc class or protocol.
if (isAnyObjCRepresentableObjectType(T))
return true;
auto NTD = T->getAnyNominal();
// Unmanaged<T> can be represented in Objective-C if T is an @objc class
// or protocol.
if (NTD == Context.getUnmanagedDecl()) {
auto BGT = T->getAs<BoundGenericType>();
if (!BGT)
return false;
assert(BGT->getGenericArgs().size() == 1);
return isAnyObjCRepresentableObjectType(BGT->getGenericArgs().front());
}
// TODO: maybe Optional<UnsafeMutablePointer<T>> should be okay?
if (wasOptional)
return false;
if (NTD) {
// If the type was imported from Clang, it is representable in Objective-C.
if (NTD->hasClangNode())
return true;
// If the type is @objc, it is representable in Objective-C.
if (NTD->isObjC())
return true;
// Pointers may be representable in ObjC.
PointerTypeKind PTK;
if (auto pointerElt = T->getAnyPointerElementType(PTK)) {
switch (PTK) {
case PTK_UnsafeMutablePointer:
case PTK_UnsafePointer: {
// An UnsafeMutablePointer<T> or UnsafePointer<T> is
// representable in Objective-C if T is a trivially
// representable type or Void.
return pointerElt->isEqual(Context.TheEmptyTupleType)
|| isTriviallyRepresentableInObjC(DC, pointerElt);
}
case PTK_AutoreleasingUnsafeMutablePointer: {
// An AutoreleasingUnsafeMutablePointer<T> is representable in ObjC if T
// is a (potentially optional) ObjC pointer type.
return isNullableObjCRepresentableObjectType(pointerElt);
}
}
}
}
// If it's a mapped type, it's representable.
fillObjCRepresentableTypeCache(DC);
if (ObjCMappedTypes.count(T->getCanonicalType()))
return true;
return false;
}
static bool
isObjCRepresentableCollection(TypeChecker &TC, const DeclContext *DC, Type T);
static bool
isElementRepresentableInObjC(TypeChecker &TC, const DeclContext *DC, Type T) {
// If you change this function, you must add or modify a test in PrintAsObjC.
// ImplicitlyUnwrappedOptional is marked bridgeable to Objective-C, but
// it's not something you can put in API signatures.
if (T->getAnyOptionalObjectType())
return false;
if (isAnyObjCRepresentableObjectType(T))
return true;
if (isObjCRepresentableCollection(TC, DC, T))
return true;
if (auto fnTy = T->getAs<AnyFunctionType>())
return fnTy->getRepresentation() == FunctionTypeRepresentation::Block;
if (!T->getAs<BoundGenericType>()) {
// Don't check this path for collections and other things that are only
// conditionally bridged to Objective-C.
ProtocolDecl *bridgingProto =
TC.getProtocol({}, KnownProtocolKind::ObjectiveCBridgeable);
if (bridgingProto &&
TC.conformsToProtocol(T, bridgingProto, const_cast<DeclContext *>(DC),
ConformanceCheckOptions())) {
return true;
}
}
return false;
}
static bool
isObjCRepresentableCollection(TypeChecker &TC, const DeclContext *DC, Type T) {
// If you change this function, you must add or modify a test in PrintAsObjC.
auto boundGeneric = T->getAs<BoundGenericType>();
if (!boundGeneric)
return false;
// Array<T> is representable when T is bridged to Objective-C.
if (auto arrayDecl = TC.Context.getArrayDecl()) {
if (boundGeneric->getDecl() == arrayDecl) {
auto elementType = boundGeneric->getGenericArgs()[0];
return isElementRepresentableInObjC(TC, DC, elementType);
}
}
// Dictionary<K, V> is representable when K and V are bridged to Objective-C.
if (auto dictDecl = TC.Context.getDictionaryDecl()) {
if (boundGeneric->getDecl() == dictDecl) {
// The key type must be bridged to Objective-C.
auto keyType = boundGeneric->getGenericArgs()[0];
if (!isElementRepresentableInObjC(TC, DC, keyType))
return false;
// The value type must be bridged to Objective-C.
auto valueType = boundGeneric->getGenericArgs()[1];
if (!isElementRepresentableInObjC(TC, DC, valueType))
return false;
return true;
}
}
// Set<T> is representable when T is bridged to Objective-C.
if (auto setDecl = TC.Context.getSetDecl()) {
if (boundGeneric->getDecl() == setDecl) {
auto elementType = boundGeneric->getGenericArgs()[0];
return isElementRepresentableInObjC(TC, DC, elementType);
}
}
return false;
}
bool TypeChecker::isRepresentableInObjC(const DeclContext *DC, Type T) {
// If you change this function, you must add or modify a test in PrintAsObjC.
if (isTriviallyRepresentableInObjC(DC, T))
return true;
// Look through one level of optional type, but remember that we did.
bool wasOptional = false;
if (auto valueType = T->getAnyOptionalObjectType()) {
T = valueType;
wasOptional = true;
}
if (auto FT = T->getAs<FunctionType>()) {
switch (FT->getRepresentation()) {
case AnyFunctionType::Representation::Thin:
return false;
case AnyFunctionType::Representation::Swift:
case AnyFunctionType::Representation::Block:
case AnyFunctionType::Representation::CFunctionPointer:
break;
}
Type Input = FT->getInput();
if (auto InputTuple = Input->getAs<TupleType>()) {
for (auto &Elt : InputTuple->getElements()) {
if (Elt.isVararg())
return false;
if (!isRepresentableInObjC(DC, Elt.getType()))
return false;
}
} else if (!isRepresentableInObjC(DC, Input)) {
return false;
}
Type Result = FT->getResult();
if (!Result->isVoid() && !isRepresentableInObjC(DC, Result))
return false;
if (FT->getExtInfo().throws())
return false;
return true;
}
if (isObjCRepresentableCollection(*this, DC, T))
return true;
// Check to see if this is a bridged type. Note that some bridged
// types are representable, but their optional type is not.
fillObjCRepresentableTypeCache(DC);
auto iter = ObjCRepresentableTypes.find(T->getCanonicalType());
if (iter != ObjCRepresentableTypes.end()) {
if (wasOptional && !iter->second)
return false;
return true;
}
return false;
}
void TypeChecker::diagnoseTypeNotRepresentableInObjC(const DeclContext *DC,
Type T,
SourceRange TypeRange) {
// Special diagnostic for tuples.
if (T->is<TupleType>()) {
if (T->isVoid())
diagnose(TypeRange.Start, diag::not_objc_empty_tuple)
.highlight(TypeRange);
else
diagnose(TypeRange.Start, diag::not_objc_tuple)
.highlight(TypeRange);
return;
}
// Special diagnostic for classes.
if (auto *CT = T->getAs<ClassType>()) {
if (!CT->getDecl()->isObjC())
diagnose(TypeRange.Start, diag::not_objc_swift_class)
.highlight(TypeRange);
return;
}
// Special diagnostic for structs.
if (T->is<StructType>()) {
diagnose(TypeRange.Start, diag::not_objc_swift_struct)
.highlight(TypeRange);
return;
}
// Special diagnostic for enums.
if (T->is<EnumType>()) {
diagnose(TypeRange.Start, diag::not_objc_swift_enum)
.highlight(TypeRange);
return;
}
// Special diagnostic for protocols and protocol compositions.
SmallVector<ProtocolDecl *, 4> Protocols;
if (T->isExistentialType(Protocols)) {
if (Protocols.empty()) {
// protocol<> is not @objc.
diagnose(TypeRange.Start, diag::not_objc_empty_protocol_composition);
return;
}
// Find a protocol that is not @objc.
for (auto PD : Protocols) {
if (!PD->isObjC()) {
diagnose(TypeRange.Start, diag::not_objc_protocol,
PD->getDeclaredType());
return;
}
}
return;
}
if (T->is<ArchetypeType>()) {
diagnose(TypeRange.Start, diag::not_objc_generic_type_param)
.highlight(TypeRange);
return;
}
if (auto fnTy = T->getAs<FunctionType>()) {
if (fnTy->getExtInfo().throws() ) {
diagnose(TypeRange.Start, diag::not_objc_function_type_throwing)
.highlight(TypeRange);
return;
}
diagnose(TypeRange.Start, diag::not_objc_function_type_param)
.highlight(TypeRange);
return;
}
}
static void
lookupAndAddRepresentableType(TypeChecker &TC,
Module *stdlib,
Identifier nativeName,
bool isOptionalRepresentable,
llvm::DenseMap<CanType, bool> &types) {
auto nativeType = lookupUniqueTypeInLibrary(TC, stdlib, nativeName);
if (!nativeType) return;
types.insert({nativeType, isOptionalRepresentable});
}
void TypeChecker::fillObjCRepresentableTypeCache(const DeclContext *DC) {
if (!ObjCMappedTypes.empty())
return;
SmallVector<Identifier, 32> StdlibTypeNames;
StdlibTypeNames.push_back(Context.getIdentifier("COpaquePointer"));
#define MAP_BUILTIN_TYPE(CLANG_BUILTIN_KIND, SWIFT_TYPE_NAME) \
StdlibTypeNames.push_back(Context.getIdentifier(#SWIFT_TYPE_NAME));
#include "swift/ClangImporter/BuiltinMappedTypes.def"
Module *Stdlib = getStdlibModule(DC);
lookupAndAddLibraryTypes(*this, Stdlib, StdlibTypeNames, ObjCMappedTypes);
StdlibTypeNames.clear();
#define MAP_BUILTIN_TYPE(_, __)
#define MAP_BUILTIN_INTEGER_TYPE(CLANG_BUILTIN_KIND, SWIFT_TYPE_NAME) \
StdlibTypeNames.push_back(Context.getIdentifier(#SWIFT_TYPE_NAME));
#include "swift/ClangImporter/BuiltinMappedTypes.def"
lookupAndAddLibraryTypes(*this, Stdlib, StdlibTypeNames, CIntegerTypes);
#define BRIDGE_TYPE(BRIDGED_MODULE, BRIDGED_TYPE, \
NATIVE_MODULE, NATIVE_TYPE, OPTIONAL_IS_BRIDGED) \
if (Context.getIdentifier(#NATIVE_MODULE) == Context.StdlibModuleName) { \
lookupAndAddRepresentableType(*this, Stdlib, \
Context.getIdentifier(#NATIVE_TYPE), \
OPTIONAL_IS_BRIDGED, \
ObjCRepresentableTypes); \
}
#include "swift/SIL/BridgedTypes.def"
Identifier ID_Darwin = Context.Id_Darwin;
if (auto DarwinModule = Context.getLoadedModule(ID_Darwin)) {
StdlibTypeNames.clear();
StdlibTypeNames.push_back(Context.getIdentifier("DarwinBoolean"));
lookupAndAddLibraryTypes(*this, DarwinModule, StdlibTypeNames,
ObjCMappedTypes);
}
Identifier ID_ObjectiveC = Context.Id_ObjectiveC;
if (auto ObjCModule = Context.getLoadedModule(ID_ObjectiveC)) {
StdlibTypeNames.clear();
StdlibTypeNames.push_back(Context.getIdentifier("Selector"));
StdlibTypeNames.push_back(Context.getIdentifier("ObjCBool"));
StdlibTypeNames.push_back(Context.getIdentifier("NSZone"));
lookupAndAddLibraryTypes(*this, ObjCModule, StdlibTypeNames,
ObjCMappedTypes);
}
Identifier ID_CoreGraphics = Context.getIdentifier("CoreGraphics");
if (auto CoreGraphicsModule = Context.getLoadedModule(ID_CoreGraphics)) {
StdlibTypeNames.clear();
StdlibTypeNames.push_back(Context.getIdentifier("CGFloat"));
lookupAndAddLibraryTypes(*this, CoreGraphicsModule, StdlibTypeNames,
ObjCMappedTypes);
}
Identifier ID_Foundation = Context.Id_Foundation;
if (auto FoundationModule = Context.getLoadedModule(ID_Foundation)) {
StdlibTypeNames.clear();
StdlibTypeNames.push_back(Context.getIdentifier("NSErrorPointer"));
lookupAndAddLibraryTypes(*this, FoundationModule, StdlibTypeNames,
ObjCMappedTypes);
}
// Pull SIMD types of size 2...4 from the SIMD module, if it exists.
Identifier ID_SIMD = Context.Id_simd;
if (auto SIMDModule = Context.getLoadedModule(ID_SIMD)) {
StdlibTypeNames.clear();
#define MAP_SIMD_TYPE(BASENAME, __) \
{ \
char name[] = #BASENAME "0"; \
for (unsigned i = 2; i <= SWIFT_MAX_IMPORTED_SIMD_ELEMENTS; ++i) { \
*(std::end(name) - 2) = '0' + i; \
StdlibTypeNames.push_back(Context.getIdentifier(name)); \
} \
}
#include "swift/ClangImporter/SIMDMappedTypes.def"
lookupAndAddLibraryTypes(*this, SIMDModule, StdlibTypeNames,
ObjCMappedTypes);
}
}
namespace {
class UnsupportedProtocolVisitor
: public TypeReprVisitor<UnsupportedProtocolVisitor>, public ASTWalker
{
TypeChecker &TC;
SmallPtrSet<ProtocolDecl *, 4> Diagnosed;
public:
UnsupportedProtocolVisitor(TypeChecker &tc) : TC(tc) { }
SmallPtrSet<ProtocolDecl *, 4> &getDiagnosedProtocols() { return Diagnosed; }
bool walkToTypeReprPre(TypeRepr *T) {
visit(T);
return true;
}
void visitIdentTypeRepr(IdentTypeRepr *T) {
auto comp = T->getComponentRange().back();
if (auto proto = dyn_cast_or_null<ProtocolDecl>(comp->getBoundDecl())) {
if (!proto->existentialTypeSupported(&TC)) {
TC.diagnose(comp->getIdLoc(), diag::unsupported_existential_type,
proto->getName());
Diagnosed.insert(proto);
}
return;
}
}
};
}
void TypeChecker::checkUnsupportedProtocolType(Decl *decl) {
if (!decl || decl->isInvalid())
return;
// Global type aliases are okay.
if (isa<TypeAliasDecl>(decl) &&
decl->getDeclContext()->isModuleScopeContext())
return;
// Non-typealias type declarations are okay.
if (isa<TypeDecl>(decl) && !isa<TypeAliasDecl>(decl))
return;
// Extensions are okay.
if (isa<ExtensionDecl>(decl))
return;
UnsupportedProtocolVisitor visitor(*this);
decl->walk(visitor);
if (auto valueDecl = dyn_cast<ValueDecl>(decl)) {
if (auto type = valueDecl->getType()) {
type.findIf([&](Type type) -> bool {
SmallVector<ProtocolDecl*, 2> protocols;
if (type->isExistentialType(protocols)) {
for (auto *proto : protocols) {
if (proto->existentialTypeSupported(this))
continue;
if (visitor.getDiagnosedProtocols().insert(proto).second) {
diagnose(valueDecl->getLoc(),
diag::unsupported_existential_type,
proto->getName());
}
}
}
return false;
});
}
}
}
void TypeChecker::checkUnsupportedProtocolType(Stmt *stmt) {
if (!stmt)
return;
UnsupportedProtocolVisitor visitor(*this);
stmt->walk(visitor);
}