blob: 9f71402d6ddea0bb2c2da82286524098dff5b33e [file] [log] [blame]
//===--- TypeCheckType.cpp - Type Validation ------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements validation for Swift types, emitting semantic errors as
// appropriate and checking default initializer values.
//
//===----------------------------------------------------------------------===//
#include "TypeChecker.h"
#include "TypeCheckAvailability.h"
#include "TypeCheckProtocol.h"
#include "TypeCheckType.h"
#include "TypoCorrection.h"
#include "swift/AST/ASTDemangler.h"
#include "swift/AST/ASTVisitor.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/DiagnosticsParse.h"
#include "swift/AST/ExistentialLayout.h"
#include "swift/AST/ForeignErrorConvention.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/GenericSignatureBuilder.h"
#include "swift/AST/NameLookup.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/PrettyStackTrace.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/SILLayout.h"
#include "swift/AST/SourceFile.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/AST/TypeLoc.h"
#include "swift/AST/TypeResolutionStage.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Basic/Statistic.h"
#include "swift/Basic/StringExtras.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "swift/Strings.h"
#include "swift/Subsystems.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/SaveAndRestore.h"
using namespace swift;
#define DEBUG_TYPE "TypeCheckType"
/// Type resolution.
TypeResolution
TypeResolution::forStructural(DeclContext *dc, TypeResolutionOptions options,
OpenUnboundGenericTypeFn unboundTyOpener) {
return TypeResolution(dc, TypeResolutionStage::Structural, options,
unboundTyOpener);
}
TypeResolution
TypeResolution::forInterface(DeclContext *dc, TypeResolutionOptions options,
OpenUnboundGenericTypeFn unboundTyOpener) {
TypeResolution result(dc, TypeResolutionStage::Interface, options,
unboundTyOpener);
result.complete.genericSig = dc->getGenericSignatureOfContext();
result.complete.builder = nullptr;
return result;
}
TypeResolution
TypeResolution::forContextual(DeclContext *dc, TypeResolutionOptions options,
OpenUnboundGenericTypeFn unboundTyOpener) {
return forContextual(dc, dc->getGenericEnvironmentOfContext(), options,
unboundTyOpener);
}
TypeResolution
TypeResolution::forContextual(DeclContext *dc, GenericEnvironment *genericEnv,
TypeResolutionOptions options,
OpenUnboundGenericTypeFn unboundTyOpener) {
TypeResolution result(dc, TypeResolutionStage::Contextual, options,
unboundTyOpener);
result.genericEnv = genericEnv;
return result;
}
TypeResolution TypeResolution::withOptions(TypeResolutionOptions opts) const {
TypeResolution result(dc, stage, opts, unboundTyOpener);
result.genericEnv = genericEnv;
result.complete = complete;
return result;
}
ASTContext &TypeResolution::getASTContext() const {
return dc->getASTContext();
}
GenericSignatureBuilder *TypeResolution::getGenericSignatureBuilder() const {
assert(stage == TypeResolutionStage::Interface);
if (!complete.builder) {
auto genericSig = getGenericSignature();
complete.builder = genericSig->getGenericSignatureBuilder();
}
return complete.builder;
}
GenericSignature TypeResolution::getGenericSignature() const {
switch (stage) {
case TypeResolutionStage::Contextual:
return dc->getGenericSignatureOfContext();
case TypeResolutionStage::Interface:
if (complete.genericSig)
return complete.genericSig;
return dc->getGenericSignatureOfContext();
case TypeResolutionStage::Structural:
return GenericSignature();
}
llvm_unreachable("unhandled stage");
}
bool TypeResolution::usesArchetypes() const {
switch (stage) {
case TypeResolutionStage::Structural:
case TypeResolutionStage::Interface:
return false;
case TypeResolutionStage::Contextual:
return true;
}
llvm_unreachable("unhandled stage");
}
Type TypeResolution::mapTypeIntoContext(Type type) const {
switch (stage) {
case TypeResolutionStage::Structural:
case TypeResolutionStage::Interface:
return type;
case TypeResolutionStage::Contextual:
return GenericEnvironment::mapTypeIntoContext(genericEnv, type);
}
llvm_unreachable("unhandled stage");
}
// FIXME: It would be nice to have a 'DescriptiveTypeKind' abstraction instead.
static DescriptiveDeclKind describeDeclOfType(Type t) {
if (!t) {
return DescriptiveDeclKind::Type;
}
if (auto *NTD = t->getAnyNominal()) {
return NTD->getDescriptiveKind();
}
return DescriptiveDeclKind::Type;
}
Type TypeResolution::resolveDependentMemberType(
Type baseTy, DeclContext *DC,
SourceRange baseRange,
ComponentIdentTypeRepr *ref) const {
// FIXME(ModQual): Reject qualified names immediately; they cannot be
// dependent member types.
Identifier refIdentifier = ref->getNameRef().getBaseIdentifier();
switch (stage) {
case TypeResolutionStage::Structural:
return DependentMemberType::get(baseTy, refIdentifier);
case TypeResolutionStage::Contextual:
llvm_unreachable("Dependent type after archetype substitution");
case TypeResolutionStage::Interface:
// Handled below.
break;
}
assert(stage == TypeResolutionStage::Interface);
if (!getGenericSignature())
return ErrorType::get(baseTy);
auto builder = getGenericSignatureBuilder();
auto baseEquivClass =
builder->resolveEquivalenceClass(
baseTy,
ArchetypeResolutionKind::CompleteWellFormed);
if (!baseEquivClass)
return ErrorType::get(baseTy);
ASTContext &ctx = baseTy->getASTContext();
// Look for a nested type with the given name.
if (auto nestedType =
baseEquivClass->lookupNestedType(*builder, refIdentifier)) {
// Record the type we found.
ref->setValue(nestedType, nullptr);
} else {
// Resolve the base to a potential archetype.
// Perform typo correction.
TypoCorrectionResults corrections(ref->getNameRef(), ref->getNameLoc());
TypeChecker::performTypoCorrection(DC, DeclRefKind::Ordinary,
MetatypeType::get(baseTy),
defaultMemberLookupOptions,
corrections, builder);
// Check whether we have a single type result.
auto singleType = cast_or_null<TypeDecl>(
corrections.getUniqueCandidateMatching([](ValueDecl *result) {
return isa<TypeDecl>(result);
}));
// If we don't have a single result, complain and fail.
if (!singleType) {
auto name = ref->getNameRef();
auto nameLoc = ref->getNameLoc();
const auto kind = describeDeclOfType(baseTy);
ctx.Diags.diagnose(nameLoc, diag::invalid_member_type, name, kind, baseTy)
.highlight(baseRange);
corrections.noteAllCandidates();
return ErrorType::get(ctx);
}
// We have a single type result. Suggest it.
ctx.Diags.diagnose(ref->getNameLoc(), diag::invalid_member_type_suggest,
baseTy, ref->getNameRef(),
singleType->getBaseName())
.fixItReplace(ref->getNameLoc().getSourceRange(),
singleType->getBaseName().userFacingName());
// Correct to the single type result.
ref->overwriteNameRef(singleType->createNameRef());
ref->setValue(singleType, nullptr);
}
auto *concrete = ref->getBoundDecl();
// If the nested type has been resolved to an associated type, use it.
if (auto assocType = dyn_cast<AssociatedTypeDecl>(concrete)) {
return DependentMemberType::get(baseTy, assocType);
}
// Otherwise, the nested type comes from a concrete type,
// or it's a typealias declared in protocol or protocol extension.
// Substitute the base type into it.
// Make sure that base type didn't get replaced along the way.
assert(baseTy->isTypeParameter());
// There are two situations possible here:
//
// 1. Member comes from the protocol, which means that it has been
// found through a conformance constraint placed on base e.g. `T: P`.
// In this case member is a `typealias` declaration located in
// protocol or protocol extension.
//
// 2. Member comes from struct/enum/class type, which means that it
// has been found through same-type constraint on base e.g. `T == Q`.
//
// If this is situation #2 we need to make sure to switch base to
// a concrete type (according to equivalence class) otherwise we'd
// end up using incorrect generic signature while attempting to form
// a substituted type for the member we found.
if (!concrete->getDeclContext()->getSelfProtocolDecl()) {
baseTy = baseEquivClass->concreteType ? baseEquivClass->concreteType
: baseEquivClass->superclass;
assert(baseTy);
}
return TypeChecker::substMemberTypeWithBase(DC->getParentModule(), concrete,
baseTy);
}
Type TypeResolution::resolveSelfAssociatedType(Type baseTy,
DeclContext *DC,
Identifier name) const {
switch (stage) {
case TypeResolutionStage::Structural:
return DependentMemberType::get(baseTy, name);
case TypeResolutionStage::Contextual:
llvm_unreachable("Dependent type after archetype substitution");
case TypeResolutionStage::Interface:
// Handled below.
break;
}
assert(stage == TypeResolutionStage::Interface);
auto builder = getGenericSignatureBuilder();
auto baseEquivClass =
builder->resolveEquivalenceClass(
baseTy,
ArchetypeResolutionKind::CompleteWellFormed);
if (!baseEquivClass)
return ErrorType::get(baseTy);
// Look for a nested type with the given name.
auto nestedType = baseEquivClass->lookupNestedType(*builder, name);
assert(nestedType);
// If the nested type has been resolved to an associated type, use it.
if (auto assocType = dyn_cast<AssociatedTypeDecl>(nestedType)) {
return DependentMemberType::get(baseTy, assocType);
}
if (nestedType->getDeclContext()->getSelfClassDecl()) {
// We found a member of a class from a protocol or protocol
// extension.
//
// Get the superclass of the 'Self' type parameter.
baseTy = (baseEquivClass->concreteType
? baseEquivClass->concreteType
: baseEquivClass->superclass);
assert(baseTy);
}
return TypeChecker::substMemberTypeWithBase(DC->getParentModule(), nestedType,
baseTy);
}
bool TypeResolution::areSameType(Type type1, Type type2) const {
if (type1->isEqual(type2))
return true;
switch (stage) {
case TypeResolutionStage::Structural:
case TypeResolutionStage::Interface:
// If neither type has a type parameter, we're done.
if (!type1->hasTypeParameter() && !type2->hasTypeParameter())
return false;
break;
case TypeResolutionStage::Contextual:
// Contextual types have already been uniqued, so the isEqual() result
// above is complete.
return false;
}
// If we have a generic signature, canonicalize using it.
if (auto genericSig = getGenericSignature()) {
// If both are type parameters, we can use a cheaper check
// that avoids transforming the type and computing anchors.
if (type1->isTypeParameter() &&
type2->isTypeParameter()) {
return genericSig->areSameTypeParameterInContext(type1, type2);
}
return genericSig->getCanonicalTypeInContext(type1)
== genericSig->getCanonicalTypeInContext(type2);
}
// Otherwise, perform a structural check.
assert(stage == TypeResolutionStage::Structural);
// FIXME: We should be performing a deeper equality check here.
// If both refer to associated types with the same name, they'll implicitly
// be considered equivalent.
auto depMem1 = type1->getAs<DependentMemberType>();
if (!depMem1) return false;
auto depMem2 = type2->getAs<DependentMemberType>();
if (!depMem2) return false;
if (depMem1->getName() != depMem2->getName()) return false;
return areSameType(depMem1->getBase(), depMem2->getBase());
}
Type TypeChecker::getArraySliceType(SourceLoc loc, Type elementType) {
ASTContext &ctx = elementType->getASTContext();
if (!ctx.getArrayDecl()) {
ctx.Diags.diagnose(loc, diag::sugar_type_not_found, 0);
return ErrorType::get(ctx);
}
return ArraySliceType::get(elementType);
}
Type TypeChecker::getOptionalType(SourceLoc loc, Type elementType) {
ASTContext &ctx = elementType->getASTContext();
if (!ctx.getOptionalDecl()) {
ctx.Diags.diagnose(loc, diag::sugar_type_not_found, 1);
return ErrorType::get(ctx);
}
return OptionalType::get(elementType);
}
Type
TypeChecker::getDynamicBridgedThroughObjCClass(DeclContext *dc,
Type dynamicType,
Type valueType) {
// We can only bridge from class or Objective-C existential types.
if (!dynamicType->satisfiesClassConstraint())
return Type();
// If the value type cannot be bridged, we're done.
if (!valueType->isPotentiallyBridgedValueType())
return Type();
return dc->getASTContext().getBridgedToObjC(dc, valueType);
}
Type TypeChecker::resolveTypeInContext(TypeDecl *typeDecl, DeclContext *foundDC,
TypeResolution resolution,
bool isSpecialized) {
auto fromDC = resolution.getDeclContext();
ASTContext &ctx = fromDC->getASTContext();
// If we found a generic parameter, map to the archetype if there is one.
if (auto genericParam = dyn_cast<GenericTypeParamDecl>(typeDecl)) {
return resolution.mapTypeIntoContext(
genericParam->getDeclaredInterfaceType());
}
if (!isSpecialized) {
// 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 *nominalType = dyn_cast<NominalTypeDecl>(typeDecl)) {
for (auto *parentDC = fromDC; !parentDC->isModuleScopeContext();
parentDC = parentDC->getParent()) {
auto *parentNominal = parentDC->getSelfNominalTypeDecl();
if (parentNominal == nominalType)
return resolution.mapTypeIntoContext(
parentDC->getDeclaredInterfaceType());
if (isa<ExtensionDecl>(parentDC)) {
auto *extendedType = parentNominal;
while (extendedType != nullptr) {
if (extendedType == nominalType)
return resolution.mapTypeIntoContext(
extendedType->getDeclaredInterfaceType());
extendedType = extendedType->getParent()->getSelfNominalTypeDecl();
}
}
}
}
// If we're inside an extension of a type alias, allow the type alias to be
// referenced without generic arguments as well.
if (auto *aliasDecl = dyn_cast<TypeAliasDecl>(typeDecl)) {
for (auto *parentDC = fromDC; !parentDC->isModuleScopeContext();
parentDC = parentDC->getParent()) {
if (auto *ext = dyn_cast<ExtensionDecl>(parentDC)) {
auto extendedType = ext->getExtendedType();
if (auto *unboundGeneric =
dyn_cast<UnboundGenericType>(extendedType.getPointer())) {
if (auto *ugAliasDecl =
dyn_cast<TypeAliasDecl>(unboundGeneric->getAnyGeneric())) {
if (ugAliasDecl == aliasDecl) {
if (resolution.getStage() == TypeResolutionStage::Structural &&
aliasDecl->getUnderlyingTypeRepr() != nullptr) {
return aliasDecl->getStructuralType();
}
return resolution.mapTypeIntoContext(
aliasDecl->getDeclaredInterfaceType());
}
extendedType = unboundGeneric->getParent();
continue;
}
}
if (auto *aliasType =
dyn_cast<TypeAliasType>(extendedType.getPointer())) {
if (aliasType->getDecl() == aliasDecl) {
if (resolution.getStage() == TypeResolutionStage::Structural &&
aliasDecl->getUnderlyingTypeRepr() != nullptr) {
return aliasDecl->getStructuralType();
}
return resolution.mapTypeIntoContext(
aliasDecl->getDeclaredInterfaceType());
}
extendedType = aliasType->getParent();
continue;
}
}
}
}
}
// Simple case -- the type is not nested inside of another type.
// However, it might be nested inside another generic context, so
// we do want to write the type in terms of interface types or
// context archetypes, depending on the resolver given to us.
if (!typeDecl->getDeclContext()->isTypeContext()) {
if (auto *aliasDecl = dyn_cast<TypeAliasDecl>(typeDecl)) {
// For a generic typealias, return the unbound generic form of the type.
if (aliasDecl->getGenericParams())
return aliasDecl->getUnboundGenericType();
// Otherwise, return the appropriate type.
if (resolution.getStage() == TypeResolutionStage::Structural &&
aliasDecl->getUnderlyingTypeRepr() != nullptr) {
return aliasDecl->getStructuralType();
}
return resolution.mapTypeIntoContext(
aliasDecl->getDeclaredInterfaceType());
}
// When a nominal type used outside its context, return the unbound
// generic form of the type.
if (auto *nominalDecl = dyn_cast<NominalTypeDecl>(typeDecl))
return nominalDecl->getDeclaredType();
assert(isa<ModuleDecl>(typeDecl));
return typeDecl->getDeclaredInterfaceType();
}
assert(foundDC);
// selfType is the self type of the context, unless the
// context is a protocol type, in which case we might have
// to use the existential type or superclass bound as a
// parent type instead.
Type selfType;
if (isa<NominalTypeDecl>(typeDecl) &&
typeDecl->getDeclContext()->getSelfProtocolDecl()) {
// When looking up a nominal type declaration inside of a
// protocol extension, always use the nominal type and
// not the protocol 'Self' type.
if (!foundDC->getDeclaredInterfaceType())
return ErrorType::get(ctx);
selfType =
resolution.mapTypeIntoContext(foundDC->getDeclaredInterfaceType());
} else {
// Otherwise, we want the protocol 'Self' type for
// substituting into alias types and associated types.
selfType = resolution.mapTypeIntoContext(foundDC->getSelfInterfaceType());
if (selfType->is<GenericTypeParamType>()) {
if (typeDecl->getDeclContext()->getSelfProtocolDecl()) {
if (isa<AssociatedTypeDecl>(typeDecl) ||
(isa<TypeAliasDecl>(typeDecl) &&
!cast<TypeAliasDecl>(typeDecl)->isGeneric())) {
// FIXME: We should use this lookup method for the Interface
// stage too, but right now that causes problems with
// Sequence.SubSequence vs Collection.SubSequence; the former
// is more canonical, but if we return that instead of the
// latter, we infer the wrong associated type in some cases,
// because we use the Sequence.SubSequence default instead of
// the Collection.SubSequence default, even when the conforming
// type wants to conform to Collection.
if (resolution.getStage() == TypeResolutionStage::Structural) {
return resolution.resolveSelfAssociatedType(selfType, foundDC,
typeDecl->getName());
} else if (auto assocType = dyn_cast<AssociatedTypeDecl>(typeDecl)) {
typeDecl = assocType->getAssociatedTypeAnchor();
}
}
}
// FIXME: Remove this once the above FIXME is addressed.
if (typeDecl->getDeclContext()->getSelfClassDecl()) {
// We found a member of a class from a protocol or protocol
// extension.
//
// Get the superclass of the 'Self' type parameter.
auto sig = foundDC->getGenericSignatureOfContext();
if (!sig)
return ErrorType::get(ctx);
auto superclassType = sig->getSuperclassBound(selfType);
if (!superclassType)
return ErrorType::get(ctx);
selfType = superclassType;
}
}
}
// Finally, substitute the base type into the member type.
return substMemberTypeWithBase(fromDC->getParentModule(), typeDecl, selfType,
resolution.usesArchetypes());
}
static TypeResolutionOptions
adjustOptionsForGenericArgs(TypeResolutionOptions options) {
options.setContext(None);
options -= TypeResolutionFlags::SILType;
return options;
}
/// This function checks if a bound generic type is UnsafePointer<Void> or
/// UnsafeMutablePointer<Void>. For these two type representations, we should
/// warn users that they are deprecated and replace them with more handy
/// UnsafeRawPointer and UnsafeMutableRawPointer, respectively.
static bool isPointerToVoid(ASTContext &Ctx, Type Ty, bool &IsMutable) {
if (Ty.isNull())
return false;
auto *BGT = Ty->getAs<BoundGenericType>();
if (!BGT)
return false;
if (BGT->getDecl() != Ctx.getUnsafePointerDecl() &&
BGT->getDecl() != Ctx.getUnsafeMutablePointerDecl())
return false;
IsMutable = BGT->getDecl() == Ctx.getUnsafeMutablePointerDecl();
assert(BGT->getGenericArgs().size() == 1);
return BGT->getGenericArgs().front()->isVoid();
}
/// Even if the type is not generic, it might be inside of a generic
/// context or have a free-standing 'where' clause, so we need to
/// those check requirements too.
///
/// Return true on success.
bool TypeChecker::checkContextualRequirements(GenericTypeDecl *decl,
Type parentTy,
SourceLoc loc,
DeclContext *dc) {
if (!parentTy || parentTy->hasUnboundGenericType() ||
parentTy->hasTypeVariable()) {
return true;
}
auto &ctx = dc->getASTContext();
SourceLoc noteLoc;
{
// We are interested in either a contextual where clause or
// a constrained extension context.
const auto ext = dyn_cast<ExtensionDecl>(decl->getDeclContext());
if (decl->getTrailingWhereClause())
noteLoc = decl->getLoc();
else if (ext && ext->isConstrainedExtension())
noteLoc = ext->getLoc();
else
return true;
if (noteLoc.isInvalid())
noteLoc = loc;
}
const auto subMap = parentTy->getContextSubstitutions(decl->getDeclContext());
const auto genericSig = decl->getGenericSignature();
if (!genericSig) {
if (loc.isValid()) {
ctx.Diags.diagnose(loc, diag::recursive_decl_reference,
decl->getDescriptiveKind(), decl->getName());
decl->diagnose(diag::kind_declared_here, DescriptiveDeclKind::Type);
}
return false;
}
const auto result =
TypeChecker::checkGenericArguments(
dc, loc, noteLoc,
decl->getDeclaredInterfaceType(),
genericSig->getGenericParams(),
genericSig->getRequirements(),
QueryTypeSubstitutionMap{subMap});
switch (result) {
case RequirementCheckResult::Failure:
case RequirementCheckResult::SubstitutionFailure:
return false;
case RequirementCheckResult::Success:
return true;
}
llvm_unreachable("invalid requirement check type");
}
static void diagnoseUnboundGenericType(Type ty, SourceLoc loc);
/// Apply generic arguments to the given type.
///
/// If the type is itself not generic, this does nothing.
///
/// This function emits diagnostics about an invalid type or the wrong number
/// of generic arguments, whereas applyUnboundGenericArguments requires this
/// to be in a correct and valid form.
///
/// \param type The generic type to which to apply arguments.
/// \param resolution The type resolution to perform.
/// \param silParams Used to look up generic parameters in SIL mode.
/// \param comp The arguments to apply with the angle bracket range for
/// diagnostics.
///
/// \returns A BoundGenericType bound to the given arguments, or null on
/// error.
///
/// \see applyUnboundGenericArguments
static Type applyGenericArguments(Type type, TypeResolution resolution,
GenericParamList *silParams,
ComponentIdentTypeRepr *comp) {
const auto options = resolution.getOptions();
auto dc = resolution.getDeclContext();
auto loc = comp->getNameLoc().getBaseNameLoc();
auto *generic = dyn_cast<GenericIdentTypeRepr>(comp);
if (!generic) {
if (auto *const unboundTy = type->getAs<UnboundGenericType>()) {
if (!options.is(TypeResolverContext::TypeAliasDecl)) {
// If the resolution object carries an opener, attempt to open
// the unbound generic type.
if (const auto openerFn = resolution.getUnboundTypeOpener())
if (const auto boundTy = openerFn(unboundTy))
return boundTy;
// Complain if we're allowed to and bail out with an error.
if (!options.contains(TypeResolutionFlags::SilenceErrors))
diagnoseUnboundGenericType(type, loc);
return ErrorType::get(resolution.getASTContext());
}
}
if (resolution.getStage() == TypeResolutionStage::Structural)
return type;
GenericTypeDecl *decl;
Type parentTy;
if (auto *aliasTy = dyn_cast<TypeAliasType>(type.getPointer())) {
decl = aliasTy->getDecl();
parentTy = aliasTy->getParent();
} else if (auto *nominalTy = type->getAs<NominalType>()) {
decl = nominalTy->getDecl();
parentTy = nominalTy->getParent();
} else {
return type;
}
if (TypeChecker::checkContextualRequirements(decl, parentTy, loc, dc))
return type;
return ErrorType::get(resolution.getASTContext());
}
if (type->hasError()) {
generic->setInvalid();
return type;
}
auto &ctx = dc->getASTContext();
auto &diags = ctx.Diags;
// We must either have an unbound generic type, or a generic type alias.
if (!type->is<UnboundGenericType>()) {
if (!options.contains(TypeResolutionFlags::SilenceErrors)) {
auto diag = diags.diagnose(loc, diag::not_a_generic_type, type);
// Don't add fixit on module type; that isn't the right type regardless
// of whether it had generic arguments.
if (!type->is<ModuleType>()) {
// When turning a SourceRange into CharSourceRange the closing angle
// brackets on nested generics are lexed as one token.
SourceRange angles = generic->getAngleBrackets();
diag.fixItRemoveChars(angles.Start,
angles.End.getAdvancedLocOrInvalid(1));
}
generic->setInvalid();
}
return type;
}
auto *unboundType = type->castTo<UnboundGenericType>();
auto *decl = unboundType->getDecl();
// 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 genericArgs = generic->getGenericArgs();
auto genericParams = decl->getGenericParams();
if (genericParams->size() != genericArgs.size()) {
if (!options.contains(TypeResolutionFlags::SilenceErrors)) {
diags.diagnose(loc, diag::type_parameter_count_mismatch, decl->getName(),
genericParams->size(), genericArgs.size(),
genericArgs.size() < genericParams->size())
.highlight(generic->getAngleBrackets());
decl->diagnose(diag::kind_declname_declared_here,
DescriptiveDeclKind::GenericType, decl->getName());
}
return ErrorType::get(ctx);
}
// In SIL mode, Optional<T> interprets T as a SIL type.
if (options.contains(TypeResolutionFlags::SILType)) {
if (auto nominal = dyn_cast<NominalTypeDecl>(decl)) {
if (nominal->isOptionalDecl()) {
// Validate the generic argument.
Type objectType = resolution.resolveType(genericArgs[0], silParams);
if (objectType->hasError()) {
return ErrorType::get(ctx);
}
return BoundGenericType::get(nominal, /*parent*/ Type(), objectType);
}
}
}
// FIXME: More principled handling of circularity.
if (!decl->getGenericSignature()) {
diags.diagnose(loc, diag::recursive_decl_reference,
decl->getDescriptiveKind(), decl->getName());
decl->diagnose(diag::kind_declared_here, DescriptiveDeclKind::Type);
return ErrorType::get(ctx);
}
// Resolve the types of the generic arguments.
auto genericResolution =
resolution.withOptions(adjustOptionsForGenericArgs(options));
SmallVector<Type, 2> args;
for (auto tyR : genericArgs) {
// Propagate failure.
Type substTy = genericResolution.resolveType(tyR, silParams);
if (!substTy || substTy->hasError())
return ErrorType::get(ctx);
args.push_back(substTy);
}
const auto result = TypeChecker::applyUnboundGenericArguments(
decl, unboundType->getParent(), loc, resolution, args);
// Migration hack.
bool isMutablePointer;
if (isPointerToVoid(dc->getASTContext(), result, isMutablePointer)) {
if (isMutablePointer)
diags.diagnose(loc, diag::use_of_void_pointer, "Mutable").
fixItReplace(generic->getSourceRange(), "UnsafeMutableRawPointer");
else
diags.diagnose(loc, diag::use_of_void_pointer, "").
fixItReplace(generic->getSourceRange(), "UnsafeRawPointer");
}
return result;
}
/// Apply generic arguments to the given type.
Type TypeChecker::applyUnboundGenericArguments(GenericTypeDecl *decl,
Type parentTy, SourceLoc loc,
TypeResolution resolution,
ArrayRef<Type> genericArgs) {
assert(genericArgs.size() == decl->getGenericParams()->size() &&
"invalid arguments, use applyGenericArguments for diagnostic emitting");
auto genericSig = decl->getGenericSignature();
assert(!genericSig.isNull());
TypeSubstitutionMap subs;
// Get the interface type for the declaration. We will be substituting
// type parameters that appear inside this type with the provided
// generic arguments.
auto resultType = decl->getDeclaredInterfaceType();
// If types involved in requirements check have either type variables
// or unbound generics, let's skip the check here, and let the solver
// do it when missing types are deduced.
bool skipRequirementsCheck = false;
// Get the substitutions for outer generic parameters from the parent
// type.
if (parentTy) {
if (parentTy->hasUnboundGenericType()) {
// If we're working with a nominal type declaration, just construct
// a bound generic type without checking the generic arguments.
if (auto *nominalDecl = dyn_cast<NominalTypeDecl>(decl)) {
return BoundGenericType::get(nominalDecl, parentTy, genericArgs);
}
assert(!resultType->hasTypeParameter());
return resultType;
}
subs = parentTy->getContextSubstitutions(decl->getDeclContext());
skipRequirementsCheck |= parentTy->hasTypeVariable();
} else if (auto genericEnv =
decl->getDeclContext()->getGenericEnvironmentOfContext()) {
auto genericSig = genericEnv->getGenericSignature();
for (auto gp : genericSig->getGenericParams()) {
subs[gp->getCanonicalType()->castTo<GenericTypeParamType>()] =
(resolution.usesArchetypes()
? genericEnv->mapTypeIntoContext(gp)
: gp);
}
}
SourceLoc noteLoc = decl->getLoc();
if (noteLoc.isInvalid())
noteLoc = loc;
// Realize the types of the generic arguments and add them to the
// substitution map.
for (unsigned i = 0, e = genericArgs.size(); i < e; ++i) {
auto origTy = genericSig->getInnermostGenericParams()[i];
auto substTy = genericArgs[i];
// Enter a substitution.
subs[origTy->getCanonicalType()->castTo<GenericTypeParamType>()] =
substTy;
skipRequirementsCheck |=
substTy->hasTypeVariable() || substTy->hasUnboundGenericType();
}
// Check the generic arguments against the requirements of the declaration's
// generic signature.
auto dc = resolution.getDeclContext();
auto *module = dc->getParentModule();
if (!skipRequirementsCheck &&
resolution.getStage() > TypeResolutionStage::Structural) {
auto result = checkGenericArguments(
dc, loc, noteLoc,
UnboundGenericType::get(decl, parentTy, dc->getASTContext()),
genericSig->getGenericParams(), genericSig->getRequirements(),
QueryTypeSubstitutionMap{subs});
switch (result) {
case RequirementCheckResult::Failure:
case RequirementCheckResult::SubstitutionFailure:
return ErrorType::get(dc->getASTContext());
case RequirementCheckResult::Success:
break;
}
}
// For a typealias, use the underlying type. We'll wrap up the result
// later.
auto typealias = dyn_cast<TypeAliasDecl>(decl);
if (typealias) {
resultType = typealias->getUnderlyingType();
}
// Apply the substitution map to the interface type of the declaration.
resultType = resultType.subst(QueryTypeSubstitutionMap{subs},
LookUpConformanceInModule(module));
// Form a sugared typealias reference.
if (typealias && (!parentTy || !parentTy->isAnyExistentialType())) {
auto genericSig = typealias->getGenericSignature();
auto subMap = SubstitutionMap::get(genericSig,
QueryTypeSubstitutionMap{subs},
LookUpConformanceInModule(module));
resultType = TypeAliasType::get(typealias, parentTy, subMap, resultType);
}
return resultType;
}
/// Diagnose a use of an unbound generic type.
static void diagnoseUnboundGenericType(Type ty, SourceLoc loc) {
auto &ctx = ty->getASTContext();
if (auto unbound = ty->getAs<UnboundGenericType>()) {
auto *decl = unbound->getDecl();
{
InFlightDiagnostic diag = ctx.Diags.diagnose(loc,
diag::generic_type_requires_arguments, ty);
SmallString<64> genericArgsToAdd;
if (TypeChecker::getDefaultGenericArgumentsString(genericArgsToAdd,
decl))
diag.fixItInsertAfter(loc, genericArgsToAdd);
}
decl->diagnose(diag::kind_declname_declared_here,
DescriptiveDeclKind::GenericType,
decl->getName());
} else {
ty.findIf([&](Type t) -> bool {
if (auto unbound = t->getAs<UnboundGenericType>()) {
ctx.Diags.diagnose(loc,
diag::generic_type_requires_arguments, t);
return true;
}
return false;
});
}
}
// Produce a diagnostic if the type we referenced was an
// associated type but the type itself was erroneous. We'll produce a
// diagnostic here if the diagnostic for the bad type witness would show up in
// a different context.
static void maybeDiagnoseBadConformanceRef(DeclContext *dc,
Type parentTy,
SourceLoc loc,
TypeDecl *typeDecl) {
auto protocol = dyn_cast<ProtocolDecl>(typeDecl->getDeclContext());
// If we weren't given a conformance, go look it up.
ProtocolConformance *conformance = nullptr;
if (protocol) {
auto conformanceRef = dc->getParentModule()->lookupConformance(
parentTy, protocol);
if (conformanceRef.isConcrete())
conformance = conformanceRef.getConcrete();
}
// If any errors have occurred, don't bother diagnosing this cross-file
// issue.
ASTContext &ctx = dc->getASTContext();
if (ctx.Diags.hadAnyError())
return;
auto diagCode =
(!protocol || (conformance && !conformance->getConditionalRequirementsIfAvailable()))
? diag::unsupported_recursion_in_associated_type_reference
: diag::broken_associated_type_witness;
ctx.Diags.diagnose(loc, diagCode, isa<TypeAliasDecl>(typeDecl),
typeDecl->getName(), parentTy);
}
/// Returns a valid type or ErrorType in case of an error.
static Type resolveTypeDecl(TypeDecl *typeDecl, DeclContext *foundDC,
TypeResolution resolution,
GenericParamList *silParams,
ComponentIdentTypeRepr *comp) {
// Resolve the type declaration to a specific type. How this occurs
// depends on the current context and where the type was found.
Type type = TypeChecker::resolveTypeInContext(
typeDecl, foundDC, resolution, isa<GenericIdentTypeRepr>(comp));
if (type->hasError() && foundDC &&
(isa<AssociatedTypeDecl>(typeDecl) || isa<TypeAliasDecl>(typeDecl))) {
auto fromDC = resolution.getDeclContext();
assert(fromDC && "No declaration context for type resolution?");
maybeDiagnoseBadConformanceRef(fromDC, foundDC->getDeclaredInterfaceType(),
comp->getNameLoc().getBaseNameLoc(),
typeDecl);
}
return applyGenericArguments(type, resolution, silParams, comp);
}
static std::string getDeclNameFromContext(DeclContext *dc,
NominalTypeDecl *nominal) {
// We don't allow an unqualified reference to a type inside an
// extension if the type is itself nested inside another type,
// eg:
//
// extension A.B { ... B ... }
//
// Instead, you must write 'A.B'. Calculate the right name to use
// for fixits.
if (!isa<ExtensionDecl>(dc)) {
SmallVector<Identifier, 2> idents;
auto *parentNominal = nominal;
while (parentNominal != nullptr) {
idents.push_back(parentNominal->getName());
parentNominal = parentNominal->getDeclContext()->getSelfNominalTypeDecl();
}
std::reverse(idents.begin(), idents.end());
std::string result;
for (auto ident : idents) {
if (!result.empty())
result += ".";
result += ident.str();
}
return result;
} else {
return std::string(nominal->getName());
}
}
/// 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.
///
/// \returns either the corrected type, if possible, or an error type to
/// that correction failed.
static Type diagnoseUnknownType(TypeResolution resolution,
Type parentType,
SourceRange parentRange,
ComponentIdentTypeRepr *comp,
NameLookupOptions lookupOptions) {
auto dc = resolution.getDeclContext();
ASTContext &ctx = dc->getASTContext();
auto &diags = ctx.Diags;
// Unqualified lookup case.
if (parentType.isNull()) {
if (comp->getNameRef().isSimpleName(ctx.Id_Self) &&
!isa<GenericIdentTypeRepr>(comp)) {
DeclContext *nominalDC = nullptr;
NominalTypeDecl *nominal = nullptr;
if ((nominalDC = dc->getInnermostTypeContext()) &&
(nominal = nominalDC->getSelfNominalTypeDecl())) {
// Attempt to refer to 'Self' within a non-protocol nominal
// type. Fix this by replacing 'Self' with the nominal type name.
assert(isa<ClassDecl>(nominal) && "Must be a class");
// Produce a Fix-It replacing 'Self' with the nominal type name.
auto name = getDeclNameFromContext(dc, nominal);
diags.diagnose(comp->getNameLoc(), diag::dynamic_self_invalid, name)
.fixItReplace(comp->getNameLoc().getSourceRange(), name);
auto type = resolution.mapTypeIntoContext(
dc->getInnermostTypeContext()->getSelfInterfaceType());
comp->overwriteNameRef(DeclNameRef(nominal->getName()));
comp->setValue(nominal, nominalDC->getParent());
return type;
}
// Attempt to refer to 'Self' from a free function.
diags.diagnose(comp->getNameLoc(), diag::dynamic_self_non_method,
dc->getParent()->isLocalContext());
return ErrorType::get(ctx);
}
// Try ignoring access control.
NameLookupOptions relookupOptions = lookupOptions;
relookupOptions |= NameLookupFlags::IgnoreAccessControl;
auto inaccessibleResults =
TypeChecker::lookupUnqualifiedType(dc, comp->getNameRef(),
comp->getLoc(), relookupOptions);
if (!inaccessibleResults.empty()) {
// FIXME: What if the unviable candidates have different levels of access?
auto first = cast<TypeDecl>(inaccessibleResults.front().getValueDecl());
diags.diagnose(comp->getNameLoc(), diag::candidate_inaccessible,
first->getBaseName(), first->getFormalAccess());
// FIXME: If any of the candidates (usually just one) are in the same
// module we could offer a fix-it.
for (auto lookupResult : inaccessibleResults)
lookupResult.getValueDecl()->diagnose(diag::kind_declared_here,
DescriptiveDeclKind::Type);
// Don't try to recover here; we'll get more access-related diagnostics
// downstream if we do.
return ErrorType::get(ctx);
}
// Fallback.
auto L = comp->getNameLoc();
SourceRange R = comp->getNameLoc().getSourceRange();
// Check if the unknown type is in the type remappings.
auto &Remapped = ctx.RemappedTypes;
auto TypeName = comp->getNameRef().getBaseIdentifier().str();
auto I = Remapped.find(TypeName);
if (I != Remapped.end()) {
auto RemappedTy = I->second->getString();
diags.diagnose(L, diag::cannot_find_type_in_scope_did_you_mean,
comp->getNameRef(), RemappedTy)
.highlight(R)
.fixItReplace(R, RemappedTy);
// Replace the computed type with the suggested type.
comp->overwriteNameRef(DeclNameRef(ctx.getIdentifier(RemappedTy)));
// HACK: 'NSUInteger' suggests both 'UInt' and 'Int'.
if (TypeName == ctx.getSwiftName(KnownFoundationEntity::NSUInteger)) {
diags.diagnose(L, diag::note_remapped_type, "UInt")
.fixItReplace(R, "UInt");
}
return I->second;
}
diags.diagnose(L, diag::cannot_find_type_in_scope,
comp->getNameRef())
.highlight(R);
return ErrorType::get(ctx);
}
// Qualified lookup case.
if (!parentType->mayHaveMembers()) {
const auto kind = describeDeclOfType(parentType);
diags
.diagnose(comp->getNameLoc(), diag::invalid_member_type,
comp->getNameRef(), kind, parentType)
.highlight(parentRange);
return ErrorType::get(ctx);
}
// Try ignoring access control.
NameLookupOptions relookupOptions = lookupOptions;
relookupOptions |= NameLookupFlags::IgnoreAccessControl;
auto inaccessibleMembers =
TypeChecker::lookupMemberType(dc, parentType, comp->getNameRef(),
relookupOptions);
if (inaccessibleMembers) {
// FIXME: What if the unviable candidates have different levels of access?
const TypeDecl *first = inaccessibleMembers.front().Member;
diags.diagnose(comp->getNameLoc(), diag::candidate_inaccessible,
first->getBaseName(), first->getFormalAccess());
// FIXME: If any of the candidates (usually just one) are in the same module
// we could offer a fix-it.
for (auto lookupResult : inaccessibleMembers)
lookupResult.Member->diagnose(diag::kind_declared_here,
DescriptiveDeclKind::Type);
// Don't try to recover here; we'll get more access-related diagnostics
// downstream if we do.
return ErrorType::get(ctx);
}
// FIXME: Typo correction!
// Lookup into a type.
if (auto moduleType = parentType->getAs<ModuleType>()) {
diags.diagnose(comp->getNameLoc(), diag::no_module_type,
comp->getNameRef(), moduleType->getModule()->getName());
} else {
LookupResult memberLookup;
// Let's try to lookup given identifier as a member of the parent type,
// this allows for more precise diagnostic, which distinguishes between
// identifier not found as a member type vs. not found at all.
NameLookupOptions memberLookupOptions = lookupOptions;
memberLookupOptions |= NameLookupFlags::IgnoreAccessControl;
memberLookup = TypeChecker::lookupMember(dc, parentType,
comp->getNameRef(),
memberLookupOptions);
// Looks like this is not a member type, but simply a member of parent type.
if (!memberLookup.empty()) {
auto member = memberLookup[0].getValueDecl();
diags.diagnose(comp->getNameLoc(), diag::invalid_member_reference,
member->getDescriptiveKind(), member->getName(),
parentType)
.highlight(parentRange);
} else {
const auto kind = describeDeclOfType(parentType);
diags
.diagnose(comp->getNameLoc(), diag::invalid_member_type,
comp->getNameRef(), kind, parentType)
.highlight(parentRange);
// Note where the type was defined, this can help diagnose if the user
// expected name lookup to find a module when there's a conflicting type.
if (auto typeDecl = parentType->getNominalOrBoundGenericNominal()) {
ctx.Diags.diagnose(typeDecl, diag::decl_declared_here,
typeDecl->getName());
}
}
}
return ErrorType::get(ctx);
}
enum class SelfTypeKind {
StaticSelf,
DynamicSelf,
InvalidSelf
};
static SelfTypeKind getSelfTypeKind(DeclContext *dc,
TypeResolutionOptions options) {
auto *typeDC = dc->getInnermostTypeContext();
// For protocols, skip this code path and find the 'Self' generic parameter.
if (typeDC->getSelfProtocolDecl())
return SelfTypeKind::InvalidSelf;
// In enums and structs, 'Self' is just a shorthand for the nominal type,
// and can be used anywhere.
if (!typeDC->getSelfClassDecl())
return SelfTypeKind::StaticSelf;
// In class methods, 'Self' is the DynamicSelfType and can only appear in
// the return type.
switch (options.getBaseContext()) {
case TypeResolverContext::FunctionResult:
case TypeResolverContext::PatternBindingDecl:
return SelfTypeKind::DynamicSelf;
case TypeResolverContext::AbstractFunctionDecl:
case TypeResolverContext::SubscriptDecl:
case TypeResolverContext::TypeAliasDecl:
case TypeResolverContext::GenericTypeAliasDecl:
// When checking a function or subscript parameter list, we have to go up
// one level to determine if we're in a local context or not.
if (dc->getParent()->isLocalContext())
return SelfTypeKind::DynamicSelf;
return SelfTypeKind::InvalidSelf;
default:
// In local functions inside classes, 'Self' is the DynamicSelfType and can
// be used anywhere.
if (dc->isLocalContext())
return SelfTypeKind::DynamicSelf;
return SelfTypeKind::InvalidSelf;
}
}
/// 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(TypeResolution resolution,
GenericParamList *silParams,
ComponentIdentTypeRepr *comp) {
const auto options = resolution.getOptions();
ASTContext &ctx = resolution.getASTContext();
auto &diags = ctx.Diags;
// Short-circuiting.
if (comp->isInvalid()) return ErrorType::get(ctx);
// If the component has already been bound to a declaration, handle
// that now.
if (auto *typeDecl = comp->getBoundDecl()) {
// Resolve the type declaration within this context.
return resolveTypeDecl(typeDecl, comp->getDeclContext(), resolution,
silParams, comp);
}
// Resolve the first component, which is the only one that requires
// unqualified name lookup.
auto DC = resolution.getDeclContext();
auto id = comp->getNameRef();
// In SIL mode, we bind generic parameters here, since name lookup
// won't find them.
if (silParams != nullptr) {
auto name = id.getBaseIdentifier();
if (auto *paramDecl = silParams->lookUpGenericParam(name)) {
comp->setValue(paramDecl, DC);
return resolveTypeDecl(paramDecl, DC, resolution,
silParams, comp);
}
}
NameLookupOptions lookupOptions = defaultUnqualifiedLookupOptions;
if (options.contains(TypeResolutionFlags::AllowUsableFromInline))
lookupOptions |= NameLookupFlags::IncludeUsableFromInline;
auto globals = TypeChecker::lookupUnqualifiedType(DC, id, comp->getLoc(),
lookupOptions);
// Process the names we found.
Type current;
TypeDecl *currentDecl = nullptr;
DeclContext *currentDC = nullptr;
bool isAmbiguous = false;
for (const auto &entry : globals) {
auto *foundDC = entry.getDeclContext();
auto *typeDecl = cast<TypeDecl>(entry.getValueDecl());
Type type = resolveTypeDecl(typeDecl, foundDC, resolution, silParams, comp);
if (type->is<ErrorType>())
return type;
// If this is the first result we found, record it.
if (current.isNull()) {
current = type;
currentDecl = typeDecl;
currentDC = foundDC;
continue;
}
// Otherwise, check for an ambiguity.
if (!resolution.areSameType(current, 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 (!options.contains(TypeResolutionFlags::SilenceErrors)) {
diags.diagnose(comp->getNameLoc(), diag::ambiguous_type_base,
comp->getNameRef())
.highlight(comp->getNameLoc().getSourceRange());
for (auto entry : globals) {
entry.getValueDecl()->diagnose(diag::found_candidate);
}
}
comp->setInvalid();
return ErrorType::get(ctx);
}
// If we found nothing, complain and give ourselves a chance to recover.
if (current.isNull()) {
// Dynamic 'Self' in the result type of a function body.
if (id.isSimpleName(ctx.Id_Self)) {
if (auto *typeDC = DC->getInnermostTypeContext()) {
// FIXME: The passed-in TypeRepr should get 'typechecked' as well.
// The issue is though that ComponentIdentTypeRepr only accepts a ValueDecl
// while the 'Self' type is more than just a reference to a TypeDecl.
auto selfType = resolution.mapTypeIntoContext(
typeDC->getSelfInterfaceType());
// Check if we can reference Self here, and if so, what kind of Self it is.
switch (getSelfTypeKind(DC, options)) {
case SelfTypeKind::StaticSelf:
return selfType;
case SelfTypeKind::DynamicSelf:
return DynamicSelfType::get(selfType, ctx);
case SelfTypeKind::InvalidSelf:
break;
}
}
}
// If we're not allowed to complain or we couldn't fix the
// source, bail out.
if (options.contains(TypeResolutionFlags::SilenceErrors))
return ErrorType::get(ctx);
return diagnoseUnknownType(resolution, nullptr, SourceRange(), comp,
lookupOptions);
}
comp->setValue(currentDecl, currentDC);
return current;
}
static void diagnoseAmbiguousMemberType(Type baseTy, SourceRange baseRange,
DeclNameRef name, DeclNameLoc nameLoc,
LookupTypeResult &lookup) {
ASTContext &ctx = baseTy->getASTContext();
auto &diags = ctx.Diags;
if (auto moduleTy = baseTy->getAs<ModuleType>()) {
diags.diagnose(nameLoc, diag::ambiguous_module_type, name,
moduleTy->getModule()->getName())
.highlight(baseRange);
} else {
diags.diagnose(nameLoc, diag::ambiguous_member_type, name, baseTy)
.highlight(baseRange);
}
for (const auto &member : lookup) {
member.Member->diagnose(diag::found_candidate_type, member.MemberType);
}
}
/// Resolve the given identifier type representation as a qualified
/// lookup within the given parent type, returning the type it
/// references.
/// \param silParams Used to look up generic parameters in SIL mode.
static Type resolveNestedIdentTypeComponent(TypeResolution resolution,
GenericParamList *silParams,
Type parentTy,
SourceRange parentRange,
ComponentIdentTypeRepr *comp) {
const auto options = resolution.getOptions();
auto DC = resolution.getDeclContext();
auto &ctx = DC->getASTContext();
auto &diags = ctx.Diags;
auto maybeDiagnoseBadMemberType = [&](TypeDecl *member, Type memberType,
AssociatedTypeDecl *inferredAssocType) {
if (options.contains(TypeResolutionFlags::SilenceErrors)) {
if (TypeChecker::isUnsupportedMemberTypeAccess(parentTy, member)
!= TypeChecker::UnsupportedMemberTypeAccessKind::None)
return ErrorType::get(ctx);
}
switch (TypeChecker::isUnsupportedMemberTypeAccess(parentTy, member)) {
case TypeChecker::UnsupportedMemberTypeAccessKind::None:
break;
case TypeChecker::UnsupportedMemberTypeAccessKind::TypeAliasOfUnboundGeneric:
case TypeChecker::UnsupportedMemberTypeAccessKind::AssociatedTypeOfUnboundGeneric:
diagnoseUnboundGenericType(parentTy, parentRange.End);
return ErrorType::get(ctx);
case TypeChecker::UnsupportedMemberTypeAccessKind::TypeAliasOfExistential:
diags.diagnose(comp->getNameLoc(), diag::typealias_outside_of_protocol,
comp->getNameRef());
return ErrorType::get(ctx);
case TypeChecker::UnsupportedMemberTypeAccessKind::AssociatedTypeOfExistential:
diags.diagnose(comp->getNameLoc(), diag::assoc_type_outside_of_protocol,
comp->getNameRef());
return ErrorType::get(ctx);
}
// Only the last component of the underlying type of a type alias may
// be an unbound generic.
if (options.is(TypeResolverContext::TypeAliasDecl)) {
if (parentTy->is<UnboundGenericType>()) {
if (!options.contains(TypeResolutionFlags::SilenceErrors))
diagnoseUnboundGenericType(parentTy, parentRange.End);
return ErrorType::get(ctx);
}
}
// Diagnose a bad conformance reference if we need to.
if (!options.contains(TypeResolutionFlags::SilenceErrors) &&
inferredAssocType && memberType->hasError()) {
maybeDiagnoseBadConformanceRef(DC, parentTy, comp->getLoc(),
inferredAssocType);
}
// If there are generic arguments, apply them now.
return applyGenericArguments(memberType, resolution,
silParams, comp);
};
// Short-circuiting.
if (comp->isInvalid()) return ErrorType::get(ctx);
// If the parent is a type parameter, the member is a dependent member,
// and we skip much of the work below.
if (parentTy->isTypeParameter()) {
if (auto memberType = resolution.resolveDependentMemberType(
parentTy, DC, parentRange, comp)) {
// Hack -- if we haven't resolved this to a declaration yet, don't
// attempt to apply generic arguments, since this will emit a
// diagnostic, and its possible that this type will become a concrete
// type later on.
if (!memberType->is<DependentMemberType>() ||
memberType->castTo<DependentMemberType>()->getAssocType()) {
return applyGenericArguments(memberType, resolution, silParams, comp);
}
return memberType;
}
}
// Phase 2: If a declaration has already been bound, use it.
if (auto *typeDecl = comp->getBoundDecl()) {
auto memberType =
TypeChecker::substMemberTypeWithBase(DC->getParentModule(), typeDecl,
parentTy);
return maybeDiagnoseBadMemberType(typeDecl, memberType, nullptr);
}
// Phase 1: Find and bind the component decl.
// Look for member types with the given name.
NameLookupOptions lookupOptions = defaultMemberLookupOptions;
if (options.contains(TypeResolutionFlags::AllowUsableFromInline))
lookupOptions |= NameLookupFlags::IncludeUsableFromInline;
LookupTypeResult memberTypes;
if (parentTy->mayHaveMembers())
memberTypes = TypeChecker::lookupMemberType(
DC, parentTy, comp->getNameRef(), 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 (!options.contains(TypeResolutionFlags::SilenceErrors))
diagnoseAmbiguousMemberType(parentTy, parentRange, comp->getNameRef(),
comp->getNameLoc(), memberTypes);
return ErrorType::get(ctx);
}
// If we didn't find anything, complain.
Type memberType;
TypeDecl *member = nullptr;
AssociatedTypeDecl *inferredAssocType = nullptr;
if (!memberTypes) {
// If we're not allowed to complain or we couldn't fix the
// source, bail out.
if (options.contains(TypeResolutionFlags::SilenceErrors))
return ErrorType::get(ctx);
memberType = diagnoseUnknownType(resolution, parentTy, parentRange, comp,
lookupOptions);
member = comp->getBoundDecl();
if (!member)
return ErrorType::get(ctx);
} else {
memberType = memberTypes.back().MemberType;
member = memberTypes.back().Member;
inferredAssocType = memberTypes.back().InferredAssociatedType;
comp->setValue(member, nullptr);
}
return maybeDiagnoseBadMemberType(member, memberType, inferredAssocType);
}
/// \param silParams Used to look up generic parameters in SIL mode.
static Type
resolveIdentTypeComponent(TypeResolution resolution,
GenericParamList *silParams,
ArrayRef<ComponentIdentTypeRepr *> components) {
auto comp = components.back();
// The first component uses unqualified lookup.
const auto parentComps = components.drop_back();
if (parentComps.empty()) {
return resolveTopLevelIdentTypeComponent(resolution, silParams,
comp);
}
// All remaining components use qualified lookup.
// Resolve the parent type.
Type parentTy = resolveIdentTypeComponent(resolution, silParams,
parentComps);
if (!parentTy || parentTy->hasError()) return parentTy;
SourceRange parentRange(parentComps.front()->getStartLoc(),
parentComps.back()->getEndLoc());
// Resolve the nested type.
return resolveNestedIdentTypeComponent(resolution, silParams,
parentTy, parentRange,
comp);
}
// Hack to apply context-specific @escaping to an AST function type.
static Type applyNonEscapingIfNecessary(Type ty,
TypeResolutionOptions options) {
// Remember whether this is a function parameter.
bool defaultNoEscape = options.is(TypeResolverContext::FunctionInput) &&
!options.hasBase(TypeResolverContext::EnumElementDecl);
// Desugar here
auto *funcTy = ty->castTo<FunctionType>();
auto extInfo = funcTy->getExtInfo();
if (defaultNoEscape && !extInfo.isNoEscape()) {
extInfo = extInfo.withNoEscape();
// We lost the sugar to flip the isNoEscape bit.
//
// FIXME: It would be better to add a new AttributedType sugared type,
// which would wrap the TypeAliasType or ParenType, and apply the
// isNoEscape bit when de-sugaring.
// <https://bugs.swift.org/browse/SR-2520>
return FunctionType::get(funcTy->getParams(), funcTy->getResult(), extInfo);
}
// Note: original sugared type
return ty;
}
/// Validate whether type associated with @autoclosure attribute is correct,
/// it supposed to be a function type with no parameters.
/// \returns true if there was an error, false otherwise.
static bool validateAutoClosureAttr(DiagnosticEngine &Diags, const SourceLoc &loc,
Type paramType) {
if (auto *fnType = paramType->getAs<FunctionType>()) {
if (fnType->getNumParams() != 0) {
Diags.diagnose(loc, diag::autoclosure_function_input_nonunit);
return true;
}
// A function type with no parameters.
return false;
}
Diags.diagnose(loc, diag::autoclosure_function_type);
return true;
}
/// Check whether the type associated with particular source location
/// has `@autoclosure` attribute, and if so, validate that such use is correct.
/// \returns true if there was an error, false otherwise.
static bool validateAutoClosureAttributeUse(DiagnosticEngine &Diags,
const TypeRepr *TR,
Type type,
TypeResolutionOptions options) {
if (!TR || TR->isInvalid())
return false;
// If is a parameter declaration marked as @autoclosure.
if (options.is(TypeResolverContext::FunctionInput)) {
if (auto *ATR = dyn_cast<AttributedTypeRepr>(TR)) {
const auto attrLoc = ATR->getAttrs().getLoc(TAK_autoclosure);
if (attrLoc.isValid())
return validateAutoClosureAttr(Diags, attrLoc, type);
}
}
// Otherwise, let's dig into the type and see if there are any
// functions with parameters marked as @autoclosure,
// such would be a part of expressions like:
// `let _: (@autoclosure () -> Int) -> Void = ...`.
bool isValid = true;
type.visit([&](Type subType) {
if (auto *fnType = subType->getAs<FunctionType>()) {
isValid &= llvm::none_of(
fnType->getParams(), [&](const FunctionType::Param &param) {
return param.isAutoClosure() &&
validateAutoClosureAttr(Diags, TR->getLoc(),
param.getPlainType());
});
}
});
return !isValid;
}
namespace {
const auto DefaultParameterConvention = ParameterConvention::Direct_Unowned;
const auto DefaultResultConvention = ResultConvention::Unowned;
/// A wrapper that ensures that the returned type from
/// \c TypeResolver::resolveType is never the null \c Type. It otherwise
/// tries to behave like \c Type, so it provides the proper conversion and
/// arrow operators.
class NeverNullType final {
public:
/// Forbid default construction.
NeverNullType() = delete;
/// Forbid construction from \c nullptr.
NeverNullType(std::nullptr_t) = delete;
public:
/// Construct a never-null Type. If \p Ty is null, a fatal error is thrown.
NeverNullType(Type Ty) : WrappedTy(Ty) {
if (WrappedTy.isNull()) {
llvm::report_fatal_error("Resolved to null type!");
}
}
/// Construct a never-null Type. If \p TyB is null, a fatal error is thrown.
NeverNullType(TypeBase *TyB) : NeverNullType(Type(TyB)) {}
operator Type() const { return WrappedTy; }
Type get() const { return WrappedTy; }
TypeBase *operator->() const { return WrappedTy.operator->(); }
private:
Type WrappedTy;
};
class TypeResolver {
const TypeResolution &resolution;
/// Used in SIL mode.
GenericParamList *genericParams;
public:
explicit TypeResolver(const TypeResolution &resolution,
GenericParamList *genericParams = nullptr)
: resolution(resolution), genericParams(genericParams) {}
NeverNullType resolveType(TypeRepr *repr, TypeResolutionOptions options);
private:
ASTContext &getASTContext() const { return resolution.getASTContext(); }
DeclContext *getDeclContext() { return resolution.getDeclContext(); }
const DeclContext *getDeclContext() const {
return resolution.getDeclContext();
}
private:
template<typename ...ArgTypes>
InFlightDiagnostic diagnose(ArgTypes &&...Args) const {
auto &diags = getASTContext().Diags;
return diags.diagnose(std::forward<ArgTypes>(Args)...);
}
template <typename... ArgTypes>
InFlightDiagnostic diagnoseInvalid(TypeRepr *repr,
ArgTypes &&... Args) const {
auto &diags = getASTContext().Diags;
repr->setInvalid();
return diags.diagnose(std::forward<ArgTypes>(Args)...);
}
NeverNullType resolveAttributedType(AttributedTypeRepr *repr,
TypeResolutionOptions options);
NeverNullType resolveAttributedType(TypeAttributes &attrs, TypeRepr *repr,
TypeResolutionOptions options);
NeverNullType
resolveASTFunctionType(FunctionTypeRepr *repr,
TypeResolutionOptions options,
AnyFunctionType::Representation representation =
AnyFunctionType::Representation::Swift,
bool noescape = false,
const clang::Type *parsedClangFunctionType = nullptr,
DifferentiabilityKind diffKind =
DifferentiabilityKind::NonDifferentiable);
SmallVector<AnyFunctionType::Param, 8> resolveASTFunctionTypeParams(
TupleTypeRepr *inputRepr, TypeResolutionOptions options,
bool requiresMappingOut, DifferentiabilityKind diffKind);
NeverNullType resolveSILFunctionType(
FunctionTypeRepr *repr, TypeResolutionOptions options,
SILCoroutineKind coroutineKind = SILCoroutineKind::None,
SILFunctionType::ExtInfoBuilder extInfoBuilder =
SILFunctionType::ExtInfoBuilder(),
ParameterConvention calleeConvention = DefaultParameterConvention,
TypeRepr *witnessmethodProtocol = nullptr);
SILParameterInfo resolveSILParameter(TypeRepr *repr,
TypeResolutionOptions options);
SILYieldInfo resolveSILYield(TypeAttributes &remainingAttrs,
TypeRepr *repr, TypeResolutionOptions options);
bool resolveSILResults(TypeRepr *repr, TypeResolutionOptions options,
SmallVectorImpl<SILYieldInfo> &yields,
SmallVectorImpl<SILResultInfo> &results,
Optional<SILResultInfo> &errorResult);
bool resolveSingleSILResult(TypeRepr *repr, TypeResolutionOptions options,
SmallVectorImpl<SILYieldInfo> &yields,
SmallVectorImpl<SILResultInfo> &results,
Optional<SILResultInfo> &errorResult);
NeverNullType resolveIdentifierType(IdentTypeRepr *IdType,
TypeResolutionOptions options);
NeverNullType resolveSpecifierTypeRepr(SpecifierTypeRepr *repr,
TypeResolutionOptions options);
NeverNullType resolveArrayType(ArrayTypeRepr *repr,
TypeResolutionOptions options);
NeverNullType resolveDictionaryType(DictionaryTypeRepr *repr,
TypeResolutionOptions options);
NeverNullType resolveOptionalType(OptionalTypeRepr *repr,
TypeResolutionOptions options);
NeverNullType resolveImplicitlyUnwrappedOptionalType(
ImplicitlyUnwrappedOptionalTypeRepr *repr,
TypeResolutionOptions options, bool isDirect);
NeverNullType resolveTupleType(TupleTypeRepr *repr,
TypeResolutionOptions options);
NeverNullType resolveCompositionType(CompositionTypeRepr *repr,
TypeResolutionOptions options);
NeverNullType resolveMetatypeType(MetatypeTypeRepr *repr,
TypeResolutionOptions options);
NeverNullType resolveProtocolType(ProtocolTypeRepr *repr,
TypeResolutionOptions options);
NeverNullType resolveSILBoxType(SILBoxTypeRepr *repr,
TypeResolutionOptions options);
NeverNullType
buildMetatypeType(MetatypeTypeRepr *repr, Type instanceType,
Optional<MetatypeRepresentation> storedRepr);
NeverNullType
buildProtocolType(ProtocolTypeRepr *repr, Type instanceType,
Optional<MetatypeRepresentation> storedRepr);
NeverNullType resolveOpaqueReturnType(TypeRepr *repr, StringRef mangledName,
unsigned ordinal,
TypeResolutionOptions options);
/// Returns true if the given type conforms to `Differentiable` in the
/// module of `DC`. If `tangentVectorEqualsSelf` is true, returns true iff
/// the given type additionally satisfies `Self == Self.TangentVector`.
bool isDifferentiable(Type type, bool tangentVectorEqualsSelf = false);
};
} // end anonymous namespace
Type TypeResolution::resolveType(TypeRepr *TyR,
GenericParamList *silParams) const {
auto &ctx = getASTContext();
auto Ty =
evaluateOrDefault(ctx.evaluator,
ResolveTypeRequest{this, TyR, silParams}, Type());
if (!Ty)
return ErrorType::get(ctx);
return Ty;
}
Type ResolveTypeRequest::evaluate(Evaluator &evaluator,
const TypeResolution *resolution,
TypeRepr *TyR,
GenericParamList *silParams) const {
const auto options = resolution->getOptions();
auto &ctx = resolution->getASTContext();
auto result =
TypeResolver(*resolution, silParams)
.resolveType(TyR, resolution->getOptions());
// 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->hasError()) {
TyR->setInvalid();
return result;
}
auto loc = TyR->getLoc();
if (options.contains(TypeResolutionFlags::SILType)
&& !result->isLegalSILType()) {
ctx.Diags.diagnose(loc, diag::illegal_sil_type, result);
return ErrorType::get(ctx);
}
if (validateAutoClosureAttributeUse(ctx.Diags, TyR, result, options))
return ErrorType::get(ctx);
return result;
}
NeverNullType 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(getASTContext());
// Strip the "is function input" bits unless this is a type that knows about
// them.
if (!isa<SpecifierTypeRepr>(repr) && !isa<TupleTypeRepr>(repr) &&
!isa<AttributedTypeRepr>(repr) && !isa<FunctionTypeRepr>(repr) &&
!isa<IdentTypeRepr>(repr) &&
!isa<ImplicitlyUnwrappedOptionalTypeRepr>(repr)) {
options.setContext(None);
}
bool isDirect = false;
if ((options & TypeResolutionFlags::Direct) && !isa<SpecifierTypeRepr>(repr)){
isDirect = true;
options -= TypeResolutionFlags::Direct;
}
switch (repr->getKind()) {
case TypeReprKind::Error:
return ErrorType::get(getASTContext());
case TypeReprKind::Attributed:
return resolveAttributedType(cast<AttributedTypeRepr>(repr), options);
case TypeReprKind::InOut:
case TypeReprKind::Shared:
case TypeReprKind::Owned:
return resolveSpecifierTypeRepr(cast<SpecifierTypeRepr>(repr), options);
case TypeReprKind::SimpleIdent:
case TypeReprKind::GenericIdent:
case TypeReprKind::CompoundIdent:
return resolveIdentifierType(cast<IdentTypeRepr>(repr), options);
case TypeReprKind::Function: {
if (!(options & TypeResolutionFlags::SILType)) {
// Default non-escaping for closure parameters
auto result =
resolveASTFunctionType(cast<FunctionTypeRepr>(repr), options);
if (result->is<FunctionType>())
return applyNonEscapingIfNecessary(result, options);
return result;
}
return resolveSILFunctionType(cast<FunctionTypeRepr>(repr), options);
}
case TypeReprKind::SILBox:
assert((options & TypeResolutionFlags::SILType) && "SILBox repr in non-SIL type context?!");
return resolveSILBoxType(cast<SILBoxTypeRepr>(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: {
auto iuoRepr = cast<ImplicitlyUnwrappedOptionalTypeRepr>(repr);
return resolveImplicitlyUnwrappedOptionalType(iuoRepr, options, isDirect);
}
case TypeReprKind::Tuple:
return resolveTupleType(cast<TupleTypeRepr>(repr), options);
case TypeReprKind::Composition:
return resolveCompositionType(cast<CompositionTypeRepr>(repr), options);
case TypeReprKind::Metatype:
return resolveMetatypeType(cast<MetatypeTypeRepr>(repr), options);
case TypeReprKind::Protocol:
return resolveProtocolType(cast<ProtocolTypeRepr>(repr), options);
case TypeReprKind::OpaqueReturn: {
// Only valid as the return type of a function, which should be handled
// during function decl type checking.
auto opaqueRepr = cast<OpaqueReturnTypeRepr>(repr);
if (!(options & TypeResolutionFlags::SilenceErrors)) {
diagnose(opaqueRepr->getOpaqueLoc(),
diag::unsupported_opaque_type);
}
// Try to resolve the constraint upper bound type as a placeholder.
options |= TypeResolutionFlags::SilenceErrors;
auto constraintType = resolveType(opaqueRepr->getConstraint(),
options);
return !constraintType->hasError() ? ErrorType::get(constraintType)
: ErrorType::get(getASTContext());
}
case TypeReprKind::Fixed:
return cast<FixedTypeRepr>(repr)->getType();
}
llvm_unreachable("all cases should be handled");
}
static Type rebuildWithDynamicSelf(ASTContext &Context, Type ty) {
if (auto metatypeTy = ty->getAs<MetatypeType>()) {
return MetatypeType::get(
rebuildWithDynamicSelf(Context, metatypeTy->getInstanceType()),
metatypeTy->getRepresentation());
} else if (auto optionalTy = ty->getOptionalObjectType()) {
return OptionalType::get(rebuildWithDynamicSelf(Context, optionalTy));
} else {
return DynamicSelfType::get(ty, Context);
}
}
NeverNullType
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);
}
NeverNullType
TypeResolver::resolveAttributedType(TypeAttributes &attrs, TypeRepr *repr,
TypeResolutionOptions options) {
// Convenience to grab the source range of a type attribute.
auto getTypeAttrRangeWithAt = [](ASTContext &ctx, SourceLoc attrLoc) {
return SourceRange(attrLoc, attrLoc.getAdvancedLoc(1));
};
// Remember whether this is a function parameter.
bool isParam = options.is(TypeResolverContext::FunctionInput);
// Remember whether this is a function result.
bool isResult = options.is(TypeResolverContext::FunctionResult);
// Remember whether this is a variadic function parameter.
bool isVariadicFunctionParam =
options.is(TypeResolverContext::VariadicFunctionInput) &&
!options.hasBase(TypeResolverContext::EnumElementDecl);
// The type we're working with, in case we want to build it differently
// based on the attributes we see.
Type ty;
// If this is a reference to an opaque return type, resolve it.
if (auto &opaque = attrs.OpaqueReturnTypeOf) {
return resolveOpaqueReturnType(repr, opaque->mangledName, opaque->index,
options);
}
// 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 = getDeclContext()->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.
auto instanceOptions = options;
instanceOptions.setContext(None);
instanceOptions -= TypeResolutionFlags::SILType;
auto instanceTy = resolveType(base, instanceOptions);
if (instanceTy->hasError())
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) {
diagnoseInvalid(repr, 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) {
diagnoseInvalid(repr, repr->getStartLoc(),
diag::sil_metatype_multiple_reprs);
}
storedRepr = MetatypeRepresentation::ObjC;
attrs.clearAttribute(TAK_objc_metatype);
}
if (instanceTy->hasError()) {
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_convention, TAK_pseudogeneric,
TAK_callee_owned, TAK_callee_guaranteed, TAK_noescape, TAK_autoclosure,
TAK_differentiable, TAK_escaping, TAK_yield_once, TAK_yield_many, TAK_async
};
auto checkUnsupportedAttr = [&](TypeAttrKind attr) {
if (attrs.has(attr)) {
diagnoseInvalid(repr, attrs.getLoc(attr), diag::unknown_attribute,
TypeAttributes::getAttrName(attr));
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 & TypeResolutionFlags::SILType)) {
for (auto silOnlyAttr : {TAK_pseudogeneric,
TAK_callee_owned,
TAK_callee_guaranteed,
TAK_noescape,
TAK_yield_once,
TAK_yield_many}) {
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 = getDeclContext()->getParentSourceFile();
if (!SF || SF->Kind != SourceFileKind::SIL) {
for (auto silOnlyAttr : {TAK_thin, TAK_thick}) {
checkUnsupportedAttr(silOnlyAttr);
}
}
bool hasFunctionAttr =
llvm::any_of(FunctionAttrs, [&attrs](const TypeAttrKind &attr) {
return attrs.has(attr);
});
// Function attributes require a syntactic function type.
auto *fnRepr = dyn_cast<FunctionTypeRepr>(repr);
auto tryParseClangType = [this](TypeAttributes::Convention &conv,
bool hasConventionCOrBlock)
-> const clang::Type * {
if (conv.ClangType.Item.empty())
return nullptr;
if (!hasConventionCOrBlock) {
diagnose(conv.ClangType.Loc,
diag::unexpected_ctype_for_non_c_convention,
conv.Name, conv.ClangType.Item);
return nullptr;
}
const clang::Type *type =
getASTContext().getClangModuleLoader()->parseClangFunctionType(
conv.ClangType.Item, conv.ClangType.Loc);
if (!type)
diagnose(conv.ClangType.Loc, diag::unable_to_parse_c_function_type,
conv.ClangType.Item);
return type;
};
if (fnRepr && hasFunctionAttr) {
const clang::Type *parsedClangFunctionType = nullptr;
if (options & TypeResolutionFlags::SILType) {
SILFunctionType::Representation rep;
TypeRepr *witnessMethodProtocol = nullptr;
auto coroutineKind = SILCoroutineKind::None;
if (attrs.has(TAK_yield_once)) {
coroutineKind = SILCoroutineKind::YieldOnce;
} else if (attrs.has(TAK_yield_many)) {
coroutineKind = SILCoroutineKind::YieldMany;
}
auto calleeConvention = ParameterConvention::Direct_Unowned;
if (attrs.has(TAK_callee_owned)) {
if (attrs.has(TAK_callee_guaranteed)) {
diagnoseInvalid(repr, 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 (!attrs.hasConvention()) {
rep = SILFunctionType::Representation::Thick;
} else {
auto convention = attrs.getConventionName();
// SIL exposes a greater number of conventions than Swift source.
auto parsedRep =
llvm::StringSwitch<Optional<SILFunctionType::Representation>>(
convention)
.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) {
diagnoseInvalid(repr, attrs.getLoc(TAK_convention),
diag::unsupported_sil_convention,
attrs.getConventionName());
rep = SILFunctionType::Representation::Thin;
} else {
rep = *parsedRep;
parsedClangFunctionType = tryParseClangType(
attrs.ConventionArguments.getValue(), shouldStoreClangType(rep));
}
if (rep == SILFunctionType::Representation::WitnessMethod) {
auto protocolName =
attrs.ConventionArguments.getValue().WitnessMethodProtocol;
witnessMethodProtocol = new (getASTContext())
SimpleIdentTypeRepr(DeclNameLoc(), protocolName);
}
}
DifferentiabilityKind diffKind = DifferentiabilityKind::NonDifferentiable;
if (attrs.has(TAK_differentiable)) {
auto *SF = getDeclContext()->getParentSourceFile();
if (SF && isDifferentiableProgrammingEnabled(*SF)) {
diffKind = attrs.linear ? DifferentiabilityKind::Linear
: DifferentiabilityKind::Normal;
} else {
diagnoseInvalid(
repr, attrs.getLoc(TAK_differentiable),
diag::
differentiable_programming_attr_used_without_required_module,
TypeAttributes::getAttrName(TAK_differentiable),
getASTContext().Id_Differentiation);
}
}
auto extInfoBuilder = SILFunctionType::ExtInfoBuilder(
rep, attrs.has(TAK_pseudogeneric), attrs.has(TAK_noescape),
attrs.has(TAK_async), diffKind, parsedClangFunctionType);
ty =
resolveSILFunctionType(fnRepr, options, coroutineKind, extInfoBuilder,
calleeConvention, witnessMethodProtocol);
if (!ty || ty->hasError())
return ty;
} else {
FunctionType::Representation rep = FunctionType::Representation::Swift;
if (attrs.hasConvention()) {
auto parsedRep =
llvm::StringSwitch<Optional<FunctionType::Representation>>(
attrs.getConventionName())
.Case("swift", FunctionType::Representation::Swift)
.Case("block", FunctionType::Representation::Block)
.Case("thin", FunctionType::Representation::Thin)
.Case("c", FunctionType::Representation::CFunctionPointer)
.Default(None);
if (!parsedRep) {
diagnoseInvalid(repr, attrs.getLoc(TAK_convention),
diag::unsupported_convention,
attrs.getConventionName());
rep = FunctionType::Representation::Swift;
} else {
rep = *parsedRep;
parsedClangFunctionType = tryParseClangType(
attrs.ConventionArguments.getValue(), shouldStoreClangType(rep));
}
}
DifferentiabilityKind diffKind = DifferentiabilityKind::NonDifferentiable;
if (attrs.has(TAK_differentiable)) {
auto *SF = getDeclContext()->getParentSourceFile();
if (SF && isDifferentiableProgrammingEnabled(*SF)) {
diffKind = attrs.linear ? DifferentiabilityKind::Linear
: DifferentiabilityKind::Normal;
} else {
diagnoseInvalid(
repr, attrs.getLoc(TAK_differentiable),
diag::
differentiable_programming_attr_used_without_required_module,
TypeAttributes::getAttrName(TAK_differentiable),
getASTContext().Id_Differentiation);
}
}
ty = resolveASTFunctionType(fnRepr, options, rep, /*noescape=*/false,
parsedClangFunctionType,
diffKind);
if (!ty || ty->hasError())
return ty;
}
}
// Validate use of @autoclosure
if (attrs.has(TAK_autoclosure)) {
bool didDiagnose = false;
if (attrs.hasConvention()) {
if (attrs.getConventionName() == "c" ||
attrs.getConventionName() == "block") {
diagnoseInvalid(repr, attrs.getLoc(TAK_convention),
diag::invalid_autoclosure_and_convention_attributes,
attrs.getConventionName());
attrs.clearAttribute(TAK_convention);
didDiagnose = true;
}
} else if (options.is(TypeResolverContext::VariadicFunctionInput) &&
!options.hasBase(TypeResolverContext::EnumElementDecl)) {
diagnoseInvalid(repr, attrs.getLoc(TAK_autoclosure),
diag::attr_not_on_variadic_parameters, "@autoclosure");
attrs.clearAttribute(TAK_autoclosure);
didDiagnose = true;
} else if (!options.is(TypeResolverContext::FunctionInput)) {
diagnoseInvalid(repr, attrs.getLoc(TAK_autoclosure),
diag::attr_only_on_parameters, "@autoclosure");
attrs.clearAttribute(TAK_autoclosure);
didDiagnose = true;
}
if (didDiagnose) {
ty = ErrorType::get(getASTContext());
}
}
auto instanceOptions = options;
instanceOptions.setContext(None);
// If we didn't build the type differently above, we might have
// a typealias pointing at a function type with the @escaping
// attribute. Resolve the type as if it were in non-parameter
// context, and then set isNoEscape if @escaping is not present.
if (!ty) ty = resolveType(repr, instanceOptions);
if (!ty || ty->hasError()) return ty;
// Type aliases inside protocols are not yet resolved in the structural
// stage of type resolution
if (ty->is<DependentMemberType>() &&
resolution.getStage() == TypeResolutionStage::Structural) {
return ty;
}
// Handle @escaping
if (ty->is<FunctionType>()) {
if (attrs.has(TAK_escaping)) {
// The attribute is meaningless except on non-variadic parameter types.
if (!isParam || options.getBaseContext() == TypeResolverContext::EnumElementDecl) {
auto loc = attrs.getLoc(TAK_escaping);
auto attrRange = getTypeAttrRangeWithAt(getASTContext(), loc);
// Try to find a better diagnostic based on how the type is being used
if (options.is(TypeResolverContext::ImmediateOptionalTypeArgument)) {
diagnoseInvalid(repr, repr->getLoc(),
diag::escaping_optional_type_argument)
.fixItRemove(attrRange);
} else {
diagnoseInvalid(repr, loc, diag::escaping_non_function_parameter)
.fixItRemove(attrRange);
}
}
attrs.clearAttribute(TAK_escaping);
} else {
// No attribute; set the isNoEscape bit if we're in parameter context.
ty = applyNonEscapingIfNecessary(ty, options);
}
}
if (attrs.has(TAK_autoclosure)) {
// If this is a situation where function type is wrapped
// into a number of parens, let's try to look through them,
// because parens are insignificant here e.g.:
//
// let _: (@autoclosure (() -> Void)) -> Void = { _ in }
if (!ty->is<FunctionType>()) {
// @autoclosure is going to be diagnosed when type of
// the parameter is validated, because that attribute
// applies to the declaration now.
repr->setInvalid();
}
attrs.clearAttribute(TAK_autoclosure);
}
if (hasFunctionAttr && !fnRepr) {
const auto diagnoseInvalidAttr = [&](TypeAttrKind kind) {
if (kind == TAK_escaping) {
Type optionalObjectType = ty->getOptionalObjectType();
if (optionalObjectType && optionalObjectType->is<AnyFunctionType>()) {
return diagnoseInvalid(repr, attrs.getLoc(kind),
diag::escaping_optional_type_argument);
}
}
return diagnoseInvalid(repr, attrs.getLoc(kind),
diag::attribute_requires_function_type,
TypeAttributes::getAttrName(kind));
};
for (auto i : FunctionAttrs) {
if (!attrs.has(i))
continue;
auto diag = diagnoseInvalidAttr(i);
// If we see @escaping among the attributes on this type, because it
// isn't a function type, we'll remove it.
if (i == TAK_escaping) {
diag.fixItRemove(getTypeAttrRangeWithAt(getASTContext(),
attrs.getLoc(TAK_escaping)));
}
attrs.clearAttribute(i);
}
} else if (hasFunctionAttr && fnRepr) {
// Remove the function attributes from the set so that we don't diagnose.
for (auto i : FunctionAttrs)
attrs.clearAttribute(i);
attrs.ConventionArguments = None;
}
if (attrs.has(TAK_noDerivative)) {
// @noDerivative is only valid on function parameters, or on function
// results in SIL.
bool isNoDerivativeAllowed =
isParam || (isResult && (options & TypeResolutionFlags::SILType));
auto *SF = getDeclContext()->getParentSourceFile();
if (SF && !isDifferentiableProgrammingEnabled(*SF)) {
diagnose(
attrs.getLoc(TAK_noDerivative),
diag::differentiable_programming_attr_used_without_required_module,
TypeAttributes::getAttrName(TAK_noDerivative),
getASTContext().Id_Differentiation);
} else if (!isNoDerivativeAllowed) {
diagnose(attrs.getLoc(TAK_noDerivative),
(isVariadicFunctionParam
? diag::attr_not_on_variadic_parameters
: diag::attr_only_on_parameters_of_differentiable),
"@noDerivative");
}
attrs.clearAttribute(TAK_noDerivative);
}
// In SIL, handle @opened (n), which creates an existential archetype.
if (attrs.has(TAK_opened)) {
if (!ty->isExistentialType()) {
diagnoseInvalid(repr, attrs.getLoc(TAK_opened), diag::opened_non_protocol,
ty);
} else {
ty = OpenedArchetypeType::get(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 = getDeclContext()->getParentSourceFile()) {
if (SF->Kind == SourceFileKind::SIL) {
if (((attrs.has(TAK_sil_weak) || attrs.has(TAK_sil_unmanaged)) &&
ty->getOptionalObjectType()) ||
(!attrs.has(TAK_sil_weak) && ty->hasReferenceSemantics())) {
ty = ReferenceStorageType::get(ty, attrs.getOwnership(),
getASTContext());
attrs.clearOwnership();
}
}
}
}
// In SIL *only*, allow @block_storage to specify a block storage type.
if ((options & TypeResolutionFlags::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 & TypeResolutionFlags::SILType) && attrs.has(TAK_box)) {
ty = SILBoxType::get(ty->getCanonicalType());
attrs.clearAttribute(TAK_box);
}
// In SIL *only*, allow @dynamic_self to specify a dynamic Self type.
if ((options & TypeResolutionFlags::SILMode) && attrs.has(TAK_dynamic_self)) {
ty = rebuildWithDynamicSelf(getASTContext(), ty);
attrs.clearAttribute(TAK_dynamic_self);
}
// In SIL *only*, allow @async to specify an async function
if ((options & TypeResolutionFlags::SILMode) && attrs.has(TAK_async)) {
if (fnRepr != nullptr) {
attrs.clearAttribute(TAK_async);
}
}
for (unsigned i = 0; i != TypeAttrKind::TAK_Count; ++i)
if (attrs.has((TypeAttrKind)i)) {
diagnoseInvalid(repr, attrs.getLoc((TypeAttrKind)i),
diag::attribute_does_not_apply_to_type);
}
return ty;
}
SmallVector<AnyFunctionType::Param, 8>
TypeResolver::resolveASTFunctionTypeParams(TupleTypeRepr *inputRepr,
TypeResolutionOptions options,
bool requiresMappingOut,
DifferentiabilityKind diffKind) {
SmallVector<AnyFunctionType::Param, 8> elements;
elements.reserve(inputRepr->getNumElements());
auto elementOptions = options.withoutContext(true);
elementOptions.setContext(TypeResolverContext::FunctionInput);
for (unsigned i = 0, end = inputRepr->getNumElements(); i != end; ++i) {
auto *eltTypeRepr = inputRepr->getElementType(i);
// If the element is a variadic parameter, resolve the parameter type as if
// it were in non-parameter position, since we want functions to be
// @escaping in this case.
auto thisElementOptions = elementOptions;
bool variadic = false;
if (inputRepr->hasEllipsis() &&
elements.size() == inputRepr->getEllipsisIndex()) {
thisElementOptions = elementOptions.withoutContext();
thisElementOptions.setContext(TypeResolverContext::VariadicFunctionInput);
variadic = true;
}
auto ty = resolveType(eltTypeRepr, thisElementOptions);
if (ty->hasError()) {
elements.emplace_back(ErrorType::get(getASTContext()));
continue;
}
// Parameters of polymorphic functions speak in terms of interface types.
if (requiresMappingOut) {
ty = ty->mapTypeOutOfContext();
}
bool autoclosure = false;
if (auto *ATR = dyn_cast<AttributedTypeRepr>(eltTypeRepr))
autoclosure = ATR->getAttrs().has(TAK_autoclosure);
ValueOwnership ownership;
auto *nestedRepr = eltTypeRepr;
// Look through parens here; other than parens, specifiers
// must appear at the top level of a parameter type.
while (auto *tupleRepr = dyn_cast<TupleTypeRepr>(nestedRepr)) {
if (!tupleRepr->isParenType())
break;
nestedRepr = tupleRepr->getElementType(0);
}
switch (nestedRepr->getKind()) {
case TypeReprKind::Shared:
ownership = ValueOwnership::Shared;
break;
case TypeReprKind::InOut:
ownership = ValueOwnership::InOut;
break;
case TypeReprKind::Owned:
ownership = ValueOwnership::Owned;
break;
default:
ownership = ValueOwnership::Default;
break;
}
bool noDerivative = false;
if (auto *attrTypeRepr = dyn_cast<AttributedTypeRepr>(eltTypeRepr)) {
if (attrTypeRepr->getAttrs().has(TAK_noDerivative)) {
if (diffKind == DifferentiabilityKind::NonDifferentiable &&
isDifferentiableProgrammingEnabled(
*getDeclContext()->getParentSourceFile()))
diagnose(eltTypeRepr->getLoc(),
diag::attr_only_on_parameters_of_differentiable,
"@noDerivative")
.highlight(eltTypeRepr->getSourceRange());
else
noDerivative = true;
}
}
auto paramFlags = ParameterTypeFlags::fromParameterType(
ty, variadic, autoclosure, /*isNonEphemeral*/ false, ownership,
noDerivative);
elements.emplace_back(ty, Identifier(), paramFlags);
}
// All non-`@noDerivative` parameters of `@differentiable` and
// `@differentiable(linear)` function types must be differentiable.
if (diffKind != DifferentiabilityKind::NonDifferentiable &&
resolution.getStage() != TypeResolutionStage::Structural) {
bool isLinear = diffKind == DifferentiabilityKind::Linear;
// Emit `@noDerivative` fixit only if there is at least one valid
// differentiability/linearity parameter. Otherwise, adding `@noDerivative`
// produces an ill-formed function type.
auto hasValidDifferentiabilityParam =
llvm::find_if(elements, [&](AnyFunctionType::Param param) {
if (param.isNoDerivative())
return false;
return isDifferentiable(param.getPlainType(),
/*tangentVectorEqualsSelf*/ isLinear);
}) != elements.end();
bool alreadyDiagnosedOneParam = false;
for (unsigned i = 0, end = inputRepr->getNumElements(); i != end; ++i) {
auto *eltTypeRepr = inputRepr->getElementType(i);
auto param = elements[i];
if (param.isNoDerivative())
continue;
auto paramType = param.getPlainType();
if (isDifferentiable(paramType, isLinear))
continue;
auto paramTypeString = paramType->getString();
auto diagnostic =
diagnose(eltTypeRepr->getLoc(),
diag::differentiable_function_type_invalid_parameter,
paramTypeString, isLinear, hasValidDifferentiabilityParam);
alreadyDiagnosedOneParam = true;
if (hasValidDifferentiabilityParam)
diagnostic.fixItInsert(eltTypeRepr->getLoc(), "@noDerivative ");
}
// Reject the case where all parameters have '@noDerivative'.
if (!alreadyDiagnosedOneParam && !hasValidDifferentiabilityParam) {
diagnose(
inputRepr->getLoc(),
diag::
differentiable_function_type_no_differentiability_parameters,
isLinear)
.highlight(inputRepr->getSourceRange());
}
}
return elements;
}
NeverNullType
TypeResolver::resolveOpaqueReturnType(TypeRepr *repr, StringRef mangledName,
unsigned ordinal,
TypeResolutionOptions options) {
// The type repr should be a generic identifier type. We don't really use
// the identifier for anything, but we do resolve the generic arguments
// to instantiate the possibly-generic opaque type.
SmallVector<Type, 4> TypeArgsBuf;
if (auto generic = dyn_cast<GenericIdentTypeRepr>(repr)) {
for (auto argRepr : generic->getGenericArgs()) {
auto argTy = resolveType(argRepr, options);
// If we cannot resolve the generic parameter, propagate the error out.
if (argTy->hasError()) {
return ErrorType::get(getASTContext());
}
TypeArgsBuf.push_back(argTy);
}
}
// Use type reconstruction to summon the opaque type decl.
Demangler demangle;
auto definingDeclNode = demangle.demangleSymbol(mangledName);
if (!definingDeclNode) {
diagnose(repr->getLoc(), diag::no_opaque_return_type_of);
return ErrorType::get(getASTContext());
}
if (definingDeclNode->getKind() == Node::Kind::Global)
definingDeclNode = definingDeclNode->getChild(0);
ASTBuilder builder(getASTContext());
auto opaqueNode =
builder.getNodeFactory().createNode(Node::Kind::OpaqueReturnTypeOf);
opaqueNode->addChild(definingDeclNode, builder.getNodeFactory());
auto TypeArgs = ArrayRef<Type>(TypeArgsBuf);
auto ty = builder.resolveOpaqueType(opaqueNode, TypeArgs, ordinal);
if (!ty || ty->hasError()) {
diagnose(repr->getLoc(), diag::no_opaque_return_type_of);
return ErrorType::get(getASTContext());
}
return ty;
}
NeverNullType TypeResolver::resolveASTFunctionType(
FunctionTypeRepr *repr, TypeResolutionOptions parentOptions,
AnyFunctionType::Representation representation, bool noescape,
const clang::Type *parsedClangFunctionType,
DifferentiabilityKind diffKind) {
Optional<llvm::SaveAndRestore<GenericParamList *>> saveGenericParams;
if (auto *genericParams = repr->getGenericParams())
saveGenericParams.emplace(this->genericParams, genericParams);
// Diagnose a couple of things that we can parse in SIL mode but we don't
// allow in formal types.
if (auto patternParams = repr->getPatternGenericParams()) {
diagnose(patternParams->getLAngleLoc(),
diag::ast_subst_function_type);
return ErrorType::get(getASTContext());
} else if (!repr->getInvocationSubstitutions().empty()) {
diagnose(repr->getInvocationSubstitutions()[0]->getStartLoc(),
diag::ast_subst_function_type);
return ErrorType::get(getASTContext());
}
TypeResolutionOptions options = None;
options |= parentOptions.withoutContext().getFlags();
auto params = resolveASTFunctionTypeParams(
repr->getArgsTypeRepr(), options,
repr->getGenericEnvironment() != nullptr, diffKind);
auto resultOptions = options.withoutContext();
resultOptions.setContext(TypeResolverContext::FunctionResult);
auto outputTy = resolveType(repr->getResultTypeRepr(), resultOptions);
if (outputTy->hasError()) {
return ErrorType::get(getASTContext());
}
// If this is a function type without parens around the parameter list,
// diagnose this and produce a fixit to add them.
if (!repr->isWarnedAbout()) {
// If someone wrote (Void) -> () in Swift 3, they probably meant
// () -> (), but (Void) -> () is (()) -> () so emit a warning
// asking if they meant () -> ().
auto args = repr->getArgsTypeRepr();
if (args->getNumElements() == 1) {
if (const auto Void =
dyn_cast<SimpleIdentTypeRepr>(args->getElementType(0))) {
if (Void->getNameRef().isSimpleName(getASTContext().Id_Void)) {
diagnose(args->getStartLoc(), diag::paren_void_probably_void)
.fixItReplace(args->getSourceRange(), "()");
repr->setWarned();
}
}
}
}
FunctionType::ExtInfoBuilder extInfoBuilder(
FunctionTypeRepresentation::Swift, noescape, repr->isThrowing(), diffKind,
/*clangFunctionType*/ nullptr);
const clang::Type *clangFnType = parsedClangFunctionType;
if (shouldStoreClangType(representation) && !clangFnType)
clangFnType =
getASTContext().getClangFunctionType(params, outputTy, representation);
auto extInfo = extInfoBuilder.withRepresentation(representation)
.withAsync(repr->isAsync())
.withClangFunctionType(clangFnType)
.build();
// SIL uses polymorphic function types to resolve overloaded member functions.
if (auto genericEnv = repr->getGenericEnvironment()) {
outputTy = outputTy->mapTypeOutOfContext();
return GenericFunctionType::get(genericEnv->getGenericSignature(),
params, outputTy, extInfo);
}
auto fnTy = FunctionType::get(params, outputTy, extInfo);
if (fnTy->hasError())
return fnTy;
// If the type is a block or C function pointer, it must be representable in
// ObjC.
switch (representation) {
case AnyFunctionType::Representation::Block:
case AnyFunctionType::Representation::CFunctionPointer:
if (!fnTy->isRepresentableIn(ForeignLanguage::ObjectiveC,
getDeclContext())) {
StringRef strName =
(representation == AnyFunctionType::Representation::Block)
? "block"
: "c";
auto extInfo2 =
extInfo.withRepresentation(AnyFunctionType::Representation::Swift);
auto simpleFnTy = FunctionType::get(params, outputTy, extInfo2);
diagnose(repr->getStartLoc(), diag::objc_convention_invalid,
simpleFnTy, strName);
}
break;
case AnyFunctionType::Representation::Thin:
case AnyFunctionType::Representation::Swift:
break;
}
// `@differentiable` and `@differentiable(linear)` function types must return
// a differentiable type.
if (extInfo.isDifferentiable() &&
resolution.getStage() != TypeResolutionStage::Structural) {
bool isLinear = diffKind == DifferentiabilityKind::Linear;
if (!isDifferentiable(outputTy, /*tangentVectorEqualsSelf*/ isLinear)) {
diagnose(repr->getResultTypeRepr()->getLoc(),
diag::differentiable_function_type_invalid_result,
outputTy->getString(), isLinear)
.highlight(repr->getResultTypeRepr()->getSourceRange());
}
}
return fnTy;
}
bool TypeResolver::isDifferentiable(Type type, bool tangentVectorEqualsSelf) {
if (resolution.getStage() != TypeResolutionStage::Contextual)
type = getDeclContext()->mapTypeIntoContext(type);
auto tanSpace = type->getAutoDiffTangentSpace(
LookUpConformanceInModule(getDeclContext()->getParentModule()));
if (!tanSpace)
return false;
// If no `Self == Self.TangentVector` requirement, return true.
if (!tangentVectorEqualsSelf)
return true;
// Otherwise, return true if `Self == Self.TangentVector`.
return type->getCanonicalType() == tanSpace->getCanonicalType();
}
NeverNullType TypeResolver::resolveSILBoxType(SILBoxTypeRepr *repr,
TypeResolutionOptions options) {
// Resolve the field types.
SmallVector<SILField, 4> fields;
{
// Resolve field types using the box type's generic environment, if it
// has one. (TODO: Field types should never refer to generic parameters
// outside the box's own environment; we should really validate that...)
TypeResolution fieldResolution{resolution};
auto *genericEnv = repr->getGenericEnvironment();
auto *genericParams = repr->getGenericParams();
if (genericParams) {
fieldResolution = TypeResolution::forContextual(
getDeclContext(), genericEnv, options,
resolution.getUnboundTypeOpener());
}
TypeResolver fieldResolver{fieldResolution,
genericParams};
for (auto &fieldRepr : repr->getFields()) {
auto fieldTy = fieldResolver.resolveType(fieldRepr.getFieldType(), options);
fields.push_back({fieldTy->getCanonicalType(), fieldRepr.isMutable()});
}
}
// Substitute out parsed context types into interface types.
CanGenericSignature genericSig;
if (auto *genericEnv = repr->getGenericEnvironment()) {
genericSig = genericEnv->getGenericSignature().getCanonicalSignature();
for (auto &field : fields) {
auto transTy = field.getLoweredType()->mapTypeOutOfContext();
field = {transTy->getCanonicalType(), field.isMutable()};
}
}
// Resolve the generic arguments.
// Start by building a TypeSubstitutionMap.
SubstitutionMap subMap;
if (genericSig) {
TypeSubstitutionMap genericArgMap;
auto params = genericSig->getGenericParams();
if (repr->getGenericArguments().size()
!= genericSig->getGenericParams().size()) {
diagnose(repr->getLoc(), diag::sil_box_arg_mismatch);
return ErrorType::get(getASTContext());
}
for (unsigned i : indices(params)) {
auto argTy = resolveType(repr->getGenericArguments()[i], options);
genericArgMap.insert({params[i], argTy->getCanonicalType()});
}
subMap = SubstitutionMap::get(
genericSig, QueryTypeSubstitutionMap{genericArgMap},
LookUpConformanceInModule(getDeclContext()->getParentModule()));
}
auto layout = SILLayout::get(getASTContext(), genericSig, fields);
return SILBoxType::get(getASTContext(), layout, subMap);
}
NeverNullType TypeResolver::resolveSILFunctionType(
FunctionTypeRepr *repr, TypeResolutionOptions options,
SILCoroutineKind coroutineKind,
SILFunctionType::ExtInfoBuilder extInfoBuilder, ParameterConvention callee,
TypeRepr *witnessMethodProtocol) {
options.setContext(None);
bool hasError = false;
// Resolve parameter and result types using the function's generic
// environment.
SmallVector<SILParameterInfo, 4> params;
SmallVector<SILYieldInfo, 4> yields;
SmallVector<SILResultInfo, 4> results;
Optional<SILResultInfo> errorResult;
// Resolve generic params in the pattern environment, if present, or
// else the function's generic environment, if it has one.
GenericParamList *genericParams = repr->getGenericParams();
if (genericParams == nullptr)
genericParams = this->genericParams;
GenericParamList *componentGenericParams = repr->getPatternGenericParams();
if (componentGenericParams == nullptr)
componentGenericParams = genericParams;
GenericEnvironment *genericEnv = repr->getGenericEnvironment();
GenericEnvironment *componentTypeEnv =
repr->getPatternGenericEnvironment()
? repr->getPatternGenericEnvironment()
: genericEnv;
{
TypeResolution functionResolution{resolution};
if (componentTypeEnv) {
functionResolution = TypeResolution::forContextual(
getDeclContext(), componentTypeEnv, options,
resolution.getUnboundTypeOpener());
}
auto argsTuple = repr->getArgsTypeRepr();
// SIL functions cannot be variadic.
if (argsTuple->hasEllipsis()) {
diagnose(argsTuple->getEllipsisLoc(), diag::sil_function_ellipsis);
}
// SIL functions cannot have parameter names.
for (auto &element : argsTuple->getElements()) {
if (element.UnderscoreLoc.isValid())
diagnose(element.UnderscoreLoc, diag::sil_function_input_label);
}
TypeResolver silResolver{functionResolution, componentGenericParams};
for (auto elt : argsTuple->getElements()) {
auto elementOptions = options;
elementOptions.setContext(TypeResolverContext::FunctionInput);
auto param = silResolver.resolveSILParameter(elt.Type, elementOptions);
params.push_back(param);
if (!param.getInterfaceType() || param.getInterfaceType()->hasError())
hasError = true;
}
{
if (silResolver.resolveSILResults(repr->getResultTypeRepr(),
options, yields,
results, errorResult)) {
hasError = true;
}
// Diagnose non-coroutines that declare yields.
if (coroutineKind == SILCoroutineKind::None && !yields.empty()) {
diagnose(repr->getResultTypeRepr()->getLoc(),
diag::sil_non_coro_yields);
hasError = true;
}
}
}
auto resolveSubstitutions = [&](GenericEnvironment *env,
ArrayRef<TypeRepr*> args,
TypeResolver &&parameterResolver) {
auto sig = env->getGenericSignature().getCanonicalSignature();
TypeSubstitutionMap subsMap;
auto params = sig->getGenericParams();
for (unsigned i : indices(args)) {
auto resolved = parameterResolver.resolveType(args[i], options);
subsMap.insert({params[i], resolved->getCanonicalType()});
}
return SubstitutionMap::get(
sig, QueryTypeSubstitutionMap{subsMap},
LookUpConformanceInModule(getDeclContext()->getParentModule()))
.getCanonical();
};
// Resolve pattern substitutions in the invocation environment, if
// applicable.
SubstitutionMap patternSubs;
if (!repr->getPatternSubstitutions().empty()) {
if (genericEnv) {
auto resolveSILParameters =
TypeResolution::forContextual(getDeclContext(), genericEnv, options,
resolution.getUnboundTypeOpener());
patternSubs = resolveSubstitutions(repr->getPatternGenericEnvironment(),
repr->getPatternSubstitutions(),
TypeResolver{resolveSILParameters,
genericParams});
} else {
patternSubs = resolveSubstitutions(repr->getPatternGenericEnvironment(),
repr->getPatternSubstitutions(),
TypeResolver{resolution,
genericParams});
}
}
// Resolve invocation substitutions if we have them.
SubstitutionMap invocationSubs;
if (!repr->getInvocationSubstitutions().empty()) {
invocationSubs = resolveSubstitutions(repr->getGenericEnvironment(),
repr->getInvocationSubstitutions(),
TypeResolver{resolution,
genericParams});
}
if (hasError) {
return ErrorType::get(getASTContext());
}
CanGenericSignature genericSig =
genericEnv ? genericEnv->getGenericSignature().getCanonicalSignature()
: CanGenericSignature();
// FIXME: Remap the parsed context types to interface types.
SmallVector<SILParameterInfo, 4> interfaceParams;
SmallVector<SILYieldInfo, 4> interfaceYields;
SmallVector<SILResultInfo, 4> interfaceResults;
Optional<SILResultInfo> interfaceErrorResult;
if (componentTypeEnv) {
for (auto &param : params) {
auto transParamType = param.getInterfaceType()->mapTypeOutOfContext()
->getCanonicalType();
interfaceParams.push_back(param.getWithInterfaceType(transParamType));
}
for (auto &yield : yields) {
auto transYieldType = yield.getInterfaceType()->mapTypeOutOfContext()
->getCanonicalType();
interfaceYields.push_back(yield.getWithInterfaceType(transYieldType));
}
for (auto &result : results) {
auto transResultType = result.getInterfaceType()->mapTypeOutOfContext()
->getCanonicalType();
interfaceResults.push_back(result.getWithInterfaceType(transResultType));
}
if (errorResult) {
auto transErrorResultType = errorResult->getInterfaceType()
->mapTypeOutOfContext()
->getCanonicalType();
interfaceErrorResult =
errorResult->getWithInterfaceType(transErrorResultType);
}
} else {
interfaceParams = params;
interfaceYields = yields;
interfaceResults = results;
interfaceErrorResult = errorResult;
}
SubstitutionMap interfacePatternSubs = patternSubs;
if (interfacePatternSubs && repr->getGenericEnvironment()) {
interfacePatternSubs =
interfacePatternSubs.mapReplacementTypesOutOfContext();
}
ProtocolConformanceRef witnessMethodConformance;
if (witnessMethodProtocol) {
auto resolved = resolveType(witnessMethodProtocol, options);
if (resolved->hasError())
return resolved;
auto protocolType = resolved->getAs<ProtocolType>();
if (!protocolType)
return ErrorType::get(getASTContext());
Type selfType = params.back().getInterfaceType();
if (patternSubs)
selfType = selfType.subst(patternSubs);
if (invocationSubs) {
selfType = selfType.subst(invocationSubs);
}
// The Self type can be nested in a few layers of metatypes (etc.).
while (auto metatypeType = selfType->getAs<MetatypeType>()) {
auto next = metatypeType->getInstanceType();
if (next->isEqual(selfType))
break;
selfType = next;
}
witnessMethodConformance = TypeChecker::conformsToProtocol(
selfType, protocolType->getDecl(), getDeclContext());
assert(witnessMethodConformance &&
"found witness_method without matching conformance");
}
auto representation = extInfoBuilder.getRepresentation();
const clang::Type *clangFnType = extInfoBuilder.getClangTypeInfo().getType();
if (shouldStoreClangType(representation) && !clangFnType) {
assert(results.size() <= 1 && yields.size() == 0 &&
"C functions and blocks have at most 1 result and 0 yields.");
auto result = results.empty() ? Optional<SILResultInfo>() : results[0];
clangFnType = getASTContext().getCanonicalClangFunctionType(
interfaceParams, result, representation);
extInfoBuilder = extInfoBuilder.withClangFunctionType(clangFnType);
}
return SILFunctionType::get(genericSig, extInfoBuilder.build(), coroutineKind,
callee, interfaceParams, interfaceYields,
interfaceResults, interfaceErrorResult,
interfacePatternSubs, invocationSubs,
getASTContext(), witnessMethodConformance);
}
SILYieldInfo TypeResolver::resolveSILYield(TypeAttributes &attrs,
TypeRepr *repr,
TypeResolutionOptions options) {
AttributedTypeRepr attrRepr(attrs, repr);
options.setContext(TypeResolverContext::FunctionInput);
SILParameterInfo paramInfo = resolveSILParameter(&attrRepr, options);
return SILYieldInfo(paramInfo.getInterfaceType(), paramInfo.getConvention());
}
SILParameterInfo TypeResolver::resolveSILParameter(
TypeRepr *repr,
TypeResolutionOptions options) {
assert(options.is(TypeResolverContext::FunctionInput) &&
"Parameters should be marked as inputs");
auto convention = DefaultParameterConvention;
Type type;
bool hadError = false;
auto differentiability =
SILParameterDifferentiability::DifferentiableOrNotApplicable;
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) {
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_in_constant,
ParameterConvention::Indirect_In_Constant);
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);
if (attrs.has(TAK_noDerivative)) {
attrs.clearAttribute(TAK_noDerivative);
differentiability = SILParameterDifferentiability::NotDifferentiable;
}
type = resolveAttributedType(attrs, attrRepr->getTypeRepr(), options);
} else {
type = resolveType(repr, options);
}
if (!type || type->hasError()) {
hadError = true;
// Diagnose types that are illegal in SIL.
} else if (!type->isLegalSILType()) {
diagnose(repr->getLoc(), diag::illegal_sil_type, type);
hadError = true;
}
if (hadError)
type = ErrorType::get(getASTContext());
return SILParameterInfo(type->getCanonicalType(), convention,
differentiability);
}
bool TypeResolver::resolveSingleSILResult(TypeRepr *repr,
TypeResolutionOptions options,
SmallVectorImpl<SILYieldInfo> &yields,
SmallVectorImpl<SILResultInfo> &ordinaryResults,
Optional<SILResultInfo> &errorResult) {
Type type;
auto convention = DefaultResultConvention;
bool isErrorResult = false;
auto differentiability =
SILResultDifferentiability::DifferentiableOrNotApplicable;
options.setContext(TypeResolverContext::FunctionResult);
if (auto attrRepr = dyn_cast<AttributedTypeRepr>(repr)) {
// Copy the attributes out; we're going to destructively modify them.
auto attrs = attrRepr->getAttrs();
// Recognize @yields.
if (attrs.has(TypeAttrKind::TAK_yields)) {
attrs.clearAttribute(TypeAttrKind::TAK_yields);
// The treatment from this point on is basically completely different.
auto yield = resolveSILYield(attrs, attrRepr->getTypeRepr(), options);
if (yield.getInterfaceType()->hasError())
return true;
yields.push_back(yield);
return false;
}
// 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 `@noDerivative`.
if (attrs.has(TAK_noDerivative)) {
attrs.clearAttribute(TAK_noDerivative);
differentiability = SILResultDifferentiability::NotDifferentiable;
}
// Recognize result conventions.
bool hadError = false;
auto checkFor = [&](TypeAttrKind tak, ResultConvention attrConv) {
if (!attrs.has(tak)) return;
if (convention != DefaultResultConvention) {
diagnose(attrs.getLoc(tak), diag::sil_function_repeat_convention,
/*result*/ 1);
hadError = true;
}
attrs.clearAttribute(tak);
convention = attrConv;
};
checkFor(TypeAttrKind::TAK_out, ResultConvention::Indirect);
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->hasError()) return true;
// Diagnose types that are illegal in SIL.
if (!type->isLegalSILType()) {
diagnose(repr->getStartLoc(), diag::illegal_sil_type, type);
return false;
}
assert(!isErrorResult || convention == ResultConvention::Owned);
SILResultInfo resolvedResult(type->getCanonicalType(), convention,
differentiability);
if (!isErrorResult) {
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()) {
diagnose(repr->getStartLoc(),
diag::sil_function_multiple_error_results);
return true;
}
errorResult = resolvedResult;
return false;
}
bool TypeResolver::resolveSILResults(TypeRepr *repr,
TypeResolutionOptions options,
SmallVectorImpl<SILYieldInfo> &yields,
SmallVectorImpl<SILResultInfo> &ordinaryResults,
Optional<SILResultInfo> &errorResult) {
if (auto tuple = dyn_cast<TupleTypeRepr>(repr)) {
bool hadError = false;
for (auto &element : tuple->getElements()) {
if (element.UnderscoreLoc.isValid())
diagnose(element.UnderscoreLoc, diag::sil_function_output_label);
}
for (auto elt : tuple->getElements()) {
if (resolveSingleSILResult(elt.Type, options,
yields, ordinaryResults, errorResult))
hadError = true;
}
return hadError;
}
return resolveSingleSILResult(repr, options,
yields, ordinaryResults, errorResult);
}
NeverNullType
TypeResolver::resolveIdentifierType(IdentTypeRepr *IdType,
TypeResolutionOptions options) {
auto ComponentRange = IdType->getComponentRange();
auto Components = llvm::makeArrayRef(ComponentRange.begin(),
ComponentRange.end());
Type result = resolveIdentTypeComponent(resolution.withOptions(options),
genericParams, Components);
if (!result || result->hasError()) {
return ErrorType::get(getASTContext());
}
if (auto moduleTy = result->getAs<ModuleType>()) {
// Allow module types only if flag is specified.
if (options.contains(TypeResolutionFlags::AllowModule))
return moduleTy;
// Otherwise, emit an error.
if (!options.contains(TypeResolutionFlags::SilenceErrors)) {
auto moduleName = moduleTy->getModule()->getName();
diagnose(Components.back()->getNameLoc(),
diag::cannot_find_type_in_scope, DeclNameRef(moduleName));
diagnose(Components.back()->getNameLoc(),
diag::note_module_as_type, moduleName);
}
Components.back()->setInvalid();
return ErrorType::get(getASTContext());
}
// Hack to apply context-specific @escaping to a typealias with an underlying
// function type.
if (result->is<FunctionType>())
result = applyNonEscapingIfNecessary(result, options);
return result;
}
NeverNullType
TypeResolver::resolveSpecifierTypeRepr(SpecifierTypeRepr *repr,
TypeResolutionOptions options) {
// inout is only valid for (non-Subscript and non-EnumCaseDecl)
// function parameters.
if (!options.is(TypeResolverContext::FunctionInput) ||
options.hasBase(TypeResolverContext::SubscriptDecl) ||
options.hasBase(TypeResolverContext::EnumElementDecl)) {
decltype(diag::attr_only_on_parameters) diagID;
if (options.getBaseContext() == TypeResolverContext::SubscriptDecl) {
diagID = diag::attr_not_on_subscript_parameters;
} else if (options.is(TypeResolverContext::VariadicFunctionInput)) {
diagID = diag::attr_not_on_variadic_parameters;
} else {
diagID = diag::attr_only_on_parameters;
}
StringRef name;
switch (repr->getKind()) {
case TypeReprKind::InOut:
name = "inout";
break;
case TypeReprKind::Shared:
name = "__shared";
break;
case TypeReprKind::Owned:
name = "__owned";
break;
default:
llvm_unreachable("unknown SpecifierTypeRepr kind");
}
diagnoseInvalid(repr, repr->getSpecifierLoc(), diagID, name);
return ErrorType::get(getASTContext());
}
if (!isa<ImplicitlyUnwrappedOptionalTypeRepr>(repr->getBase())) {
// Anything within the inout isn't a parameter anymore.
options.setContext(None);
}
return resolveType(repr->getBase(), options);
}
NeverNullType TypeResolver::resolveArrayType(ArrayTypeRepr *repr,
TypeResolutionOptions options) {
auto baseTy = resolveType(repr->getBase(), options.withoutContext());
if (baseTy->hasError()) {
return ErrorType::get(getASTContext());
}
auto sliceTy =
TypeChecker::getArraySliceType(repr->getBrackets().Start, baseTy);
if (sliceTy->hasError())
return ErrorType::get(getASTContext());
return sliceTy;
}
NeverNullType
TypeResolver::resolveDictionaryType(DictionaryTypeRepr *repr,
TypeResolutionOptions options) {
options = adjustOptionsForGenericArgs(options);
auto keyTy = resolveType(repr->getKey(), options.withoutContext());
if (keyTy->hasError()) {
return ErrorType::get(getASTContext());
}
auto valueTy = resolveType(repr->getValue(), options.withoutContext());
if (valueTy->hasError()) {
return ErrorType::get(getASTContext());
}
auto *const dictDecl = getASTContext().getDictionaryDecl();
if (!dictDecl) {
getASTContext().Diags.diagnose(repr->getBrackets().Start,
diag::sugar_type_not_found, 3);
return ErrorType::get(getASTContext());
}
if (!TypeChecker::applyUnboundGenericArguments(
dictDecl, nullptr, repr->getStartLoc(), resolution,
{keyTy, valueTy})) {
assert(getASTContext().Diags.hadAnyError());
return ErrorType::get(getASTContext());
}
return DictionaryType::get(keyTy, valueTy);
}
NeverNullType TypeResolver::resolveOptionalType(OptionalTypeRepr *repr,
TypeResolutionOptions options) {
TypeResolutionOptions elementOptions = options.withoutContext(true);
elementOptions.setContext(TypeResolverContext::ImmediateOptionalTypeArgument);
auto baseTy = resolveType(repr->getBase(), elementOptions);
if (baseTy->hasError()) {
return ErrorType::get(getASTContext());
}
auto optionalTy = TypeChecker::getOptionalType(repr->getQuestionLoc(),
baseTy);
if (optionalTy->hasError()) {
return ErrorType::get(getASTContext());
}
return optionalTy;
}
NeverNullType TypeResolver::resolveImplicitlyUnwrappedOptionalType(
ImplicitlyUnwrappedOptionalTypeRepr *repr, TypeResolutionOptions options,
bool isDirect) {
TypeResolutionFlags allowIUO = TypeResolutionFlags::SILType;
bool doDiag = false;
switch (options.getContext()) {
case TypeResolverContext::None:
if (!isDirect || !(options & allowIUO))
doDiag = true;
break;
case TypeResolverContext::FunctionInput:
case TypeResolverContext::FunctionResult:
case TypeResolverContext::PatternBindingDecl:
doDiag = !isDirect;
break;
case TypeResolverContext::VariadicFunctionInput:
case TypeResolverContext::ForEachStmt:
case TypeResolverContext::ExtensionBinding:
case TypeResolverContext::ExplicitCastExpr:
case TypeResolverContext::SubscriptDecl:
case TypeResolverContext::EnumElementDecl:
case TypeResolverContext::EnumPatternPayload:
case TypeResolverContext::TypeAliasDecl:
case TypeResolverContext::GenericTypeAliasDecl:
case TypeResolverContext::GenericRequirement:
case TypeResolverContext::ImmediateOptionalTypeArgument:
case TypeResolverContext::InExpression:
case TypeResolverContext::EditorPlaceholderExpr:
case TypeResolverContext::AbstractFunctionDecl:
case TypeResolverContext::ClosureExpr:
doDiag = true;
break;
}
if (doDiag && !options.contains(TypeResolutionFlags::SilenceErrors)) {
// Prior to Swift 5, we allow 'as T!' and turn it into a disjunction.
if (getASTContext().isSwiftVersionAtLeast(5)) {
diagnose(repr->getStartLoc(),
diag::implicitly_unwrapped_optional_in_illegal_position)
.fixItReplace(repr->getExclamationLoc(), "?");
} else if (options.is(TypeResolverContext::ExplicitCastExpr)) {
diagnose(
repr->getStartLoc(),
diag::implicitly_unwrapped_optional_deprecated_in_this_position);
} else {
diagnose(
repr->getStartLoc(),
diag::implicitly_unwrapped_optional_in_illegal_position_interpreted_as_optional)
.fixItReplace(repr->getExclamationLoc(), "?");
}
}
TypeResolutionOptions elementOptions = options.withoutContext(true);
elementOptions.setContext(TypeResolverContext::ImmediateOptionalTypeArgument);
auto baseTy = resolveType(repr->getBase(), elementOptions);
if (baseTy->hasError()) {
return ErrorType::get(getASTContext());
}
auto uncheckedOptionalTy =
TypeChecker::getOptionalType(repr->getExclamationLoc(), baseTy);
if (uncheckedOptionalTy->hasError()) {
return ErrorType::get(getASTContext());
}
return uncheckedOptionalTy;
}
NeverNullType TypeResolver::resolveTupleType(TupleTypeRepr *repr,
TypeResolutionOptions options) {
SmallVector<TupleTypeElt, 8> elements;
elements.reserve(repr->getNumElements());
llvm::SmallDenseSet<Identifier> seenEltNames;
seenEltNames.reserve(repr->getNumElements());
auto elementOptions = options;
if (!repr->isParenType()) {
elementOptions = elementOptions.withoutContext(true);
}
// Variadic tuples are not permitted.
bool complained = false;
if (repr->hasEllipsis()) {
diagnose(repr->getEllipsisLoc(), diag::tuple_ellipsis);
repr->removeEllipsis();
complained = true;
}
bool hadError = false;
bool foundDupLabel = false;
for (unsigned i = 0, end = repr->getNumElements(); i != end; ++i) {
auto *tyR = repr->getElementType(i);
auto ty = resolveType(tyR, elementOptions);
if (ty->hasError())
hadError = true;
auto eltName = repr->getElementName(i);
elements.emplace_back(ty, eltName, ParameterTypeFlags());
if (eltName.empty())
continue;
if (seenEltNames.count(eltName) == 1) {
foundDupLabel = true;
}
seenEltNames.insert(eltName);
}
if (hadError)
return ErrorType::get(getASTContext());
// Single-element labeled tuples are not permitted outside of declarations
// or SIL, either.
if (elements.size() == 1 && elements[0].hasName()
&& !(options & TypeResolutionFlags::SILType)) {
if (!complained) {
diagnose(repr->getElementNameLoc(0), diag::tuple_single_element)
.fixItRemoveChars(repr->getElementNameLoc(0),
repr->getElementType(0)->getStartLoc());
}
elements[0] = TupleTypeElt(elements[0].getType());
}
// Tuples with duplicate element labels are not permitted
if (foundDupLabel) {
diagnose(repr->getLoc(), diag::tuple_duplicate_label);
}
return TupleType::get(elements, getASTContext());
}
NeverNullType
TypeResolver::resolveCompositionType(CompositionTypeRepr *repr,
TypeResolutionOptions options) {
// Note that the superclass type will appear as part of one of the
// types in 'Members', so it's not used when constructing the
// fully-realized type below -- but we just record it to make sure
// there is only one superclass.
Type SuperclassType;
SmallVector<Type, 4> Members;
// Whether we saw at least one protocol. A protocol composition
// must either be empty (in which case it is Any or AnyObject),
// or if it has a superclass constraint, have at least one protocol.
bool HasProtocol = false;
auto checkSuperclass = [&](SourceLoc loc, Type t) -> bool {
if (SuperclassType && !SuperclassType->isEqual(t)) {
diagnose(loc, diag::protocol_composition_one_class, t,
SuperclassType);
return true;
}
SuperclassType = t;
return false;
};
for (auto tyR : repr->getTypes()) {
auto ty = resolveType(tyR, options.withoutContext());
if (ty->hasError()) return ty;
auto nominalDecl = ty->getAnyNominal();
if (nominalDecl && isa<ClassDecl>(nominalDecl)) {
if (checkSuperclass(tyR->getStartLoc(), ty))
continue;
Members.push_back(ty);
continue;
}
if (ty->isExistentialType()) {
auto layout = ty->getExistentialLayout();
if (auto superclass = layout.explicitSuperclass)
if (checkSuperclass(tyR->getStartLoc(), superclass))
continue;
if (!layout.getProtocols().empty())
HasProtocol = true;
Members.push_back(ty);
continue;
}
diagnose(tyR->getStartLoc(),
diag::invalid_protocol_composition_member,
ty);
}
// Avoid confusing diagnostics ('MyClass' not convertible to 'MyClass',
// etc) by collapsing a composition consisting of a single class down
// to the class itself.
if (SuperclassType && !HasProtocol)
return SuperclassType;
// In user-written types, AnyObject constraints always refer to the
// AnyObject type in the standard library.
return ProtocolCompositionType::get(getASTContext(), Members,
/*HasExplicitAnyObject=*/false);
}
NeverNullType TypeResolver::resolveMetatypeType(MetatypeTypeRepr *repr,
TypeResolutionOptions options) {
// The instance type of a metatype is always abstract, not SIL-lowered.
auto ty = resolveType(repr->getBase(), options.withoutContext());
if (ty->hasError()) {
return ErrorType::get(getASTContext());
}
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 & TypeResolutionFlags::SILType) {
diagnose(repr->getStartLoc(), diag::sil_metatype_without_repr);
storedRepr = MetatypeRepresentation::Thick;
}
return buildMetatypeType(repr, ty, storedRepr);
}
NeverNullType
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);
}
}
NeverNullType TypeResolver::resolveProtocolType(ProtocolTypeRepr *repr,
TypeResolutionOptions options) {
// The instance type of a metatype is always abstract, not SIL-lowered.
auto ty = resolveType(repr->getBase(), options.withoutContext());
if (ty->hasError()) {
return ErrorType::get(getASTContext());
}
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 & TypeResolutionFlags::SILType) {
diagnose(repr->getStartLoc(), diag::sil_metatype_without_repr);
storedRepr = MetatypeRepresentation::Thick;
}
return buildProtocolType(repr, ty, storedRepr);
}
NeverNullType
TypeResolver::buildProtocolType(ProtocolTypeRepr *repr, Type instanceType,
Optional<MetatypeRepresentation> storedRepr) {
if (!instanceType->isAnyExistentialType()) {
diagnose(repr->getProtocolLoc(), diag::dot_protocol_on_non_existential,
instanceType);
return ErrorType::get(getASTContext());
}
return MetatypeType::get(instanceType, storedRepr);
}
Type TypeChecker::substMemberTypeWithBase(ModuleDecl *module,
TypeDecl *member,
Type baseTy,
bool useArchetypes) {
Type sugaredBaseTy = baseTy;
// For type members of a base class, make sure we use the right
// derived class as the parent type. If the base type is an error
// type, we have an invalid extension, so do nothing.
if (!baseTy->is<ErrorType>()) {
if (auto *ownerClass = member->getDeclContext()->getSelfClassDecl()) {
baseTy = baseTy->getSuperclassForDecl(ownerClass, useArchetypes);
}
}
if (baseTy->is<ModuleType>()) {
baseTy = Type();
sugaredBaseTy = Type();
}
// The declared interface type for a generic type will have the type
// arguments; strip them off.
if (auto *nominalDecl = dyn_cast<NominalTypeDecl>(member)) {
// If the base type is not a nominal type, we might be looking up a
// nominal member of a generic parameter. This is not supported right
// now, but at least don't crash.
if (member->getDeclContext()->getSelfProtocolDecl())
return nominalDecl->getDeclaredType();
if (!isa<ProtocolDecl>(nominalDecl) &&
nominalDecl->getGenericParams()) {
return UnboundGenericType::get(
nominalDecl, baseTy,
nominalDecl->getASTContext());
}
if (baseTy && baseTy->is<ErrorType>())
return baseTy;
return NominalType::get(
nominalDecl, baseTy,
nominalDecl->getASTContext());
}
auto *aliasDecl = dyn_cast<TypeAliasDecl>(member);
if (aliasDecl) {
if (aliasDecl->getGenericParams()) {
return UnboundGenericType::get(
aliasDecl, baseTy,
aliasDecl->getASTContext());
}
}
Type resultType;
auto memberType = aliasDecl ? aliasDecl->getUnderlyingType()
: member->getDeclaredInterfaceType();
SubstitutionMap subs;
if (baseTy) {
// Cope with the presence of unbound generic types, which are ill-formed
// at this point but break the invariants of getContextSubstitutionMap().
if (baseTy->hasUnboundGenericType()) {
if (memberType->hasTypeParameter())
return ErrorType::get(memberType);
return memberType;
}
if (baseTy->is<ErrorType>())
return ErrorType::get(memberType);
subs = baseTy->getContextSubstitutionMap(module, member->getDeclContext());
resultType = memberType.subst(subs);
} else {
resultType = memberType;
}
// If we're referring to a typealias within a generic context, build
// a sugared alias type.
if (aliasDecl && (!sugaredBaseTy || !sugaredBaseTy->isAnyExistentialType())) {
resultType = TypeAliasType::get(aliasDecl, sugaredBaseTy, subs, resultType);
}
return resultType;
}
namespace {
class UnsupportedProtocolVisitor
: public TypeReprVisitor<UnsupportedProtocolVisitor>, public ASTWalker
{
ASTContext &Ctx;
bool checkStatements;
bool hitTopStmt;
public:
UnsupportedProtocolVisitor(ASTContext &ctx, bool checkStatements)
: Ctx(ctx), checkStatements(checkStatements), hitTopStmt(false) { }
bool walkToTypeReprPre(TypeRepr *T) override {
if (T->isInvalid())
return false;
if (auto compound = dyn_cast<CompoundIdentTypeRepr>(T)) {
// Only visit the last component to check, because nested typealiases in
// existentials are okay.
visit(compound->getComponentRange().back());
return false;
}
// Arbitrary protocol constraints are OK on opaque types.
if (isa<OpaqueReturnTypeRepr>(T))
return false;
visit(T);
return true;
}
std::pair<bool, Stmt*> walkToStmtPre(Stmt *S) override {
if (checkStatements && !hitTopStmt) {
hitTopStmt = true;
return { true, S };
}
return { false, S };
}
bool walkToDeclPre(Decl *D) override {
return !checkStatements;
}
void visitTypeRepr(TypeRepr *T) {
// Do nothing for all TypeReprs except the ones listed below.
}
void visitIdentTypeRepr(IdentTypeRepr *T) {
if (T->isInvalid())
return;
auto comp = T->getComponentRange().back();
if (auto *proto = dyn_cast_or_null<ProtocolDecl>(comp->getBoundDecl())) {
if (!proto->existentialTypeSupported()) {
Ctx.Diags.diagnose(comp->getNameLoc(),
diag::unsupported_existential_type,
proto->getName());
T->setInvalid();
}
} else if (auto *alias = dyn_cast_or_null<TypeAliasDecl>(comp->getBoundDecl())) {
auto type = Type(alias->getDeclaredInterfaceType()->getDesugaredType());
type.findIf([&](Type type) -> bool {
if (T->isInvalid())
return false;
if (type->isExistentialType()) {
auto layout = type->getExistentialLayout();
for (auto *proto : layout.getProtocols()) {
auto *protoDecl = proto->getDecl();
if (protoDecl->existentialTypeSupported())
continue;
Ctx.Diags.diagnose(comp->getNameLoc(),
diag::unsupported_existential_type,
protoDecl->getName());
T->setInvalid();
}
}
return false;
});
}
}
void visitRequirements(ArrayRef<RequirementRepr> reqts) {
for (auto reqt : reqts) {
if (reqt.getKind() == RequirementReprKind::SameType) {
if (auto *repr = reqt.getFirstTypeRepr())
repr->walk(*this);
if (auto *repr = reqt.getSecondTypeRepr())
repr->walk(*this);
}
}
}
};
} // end anonymous namespace
void TypeChecker::checkUnsupportedProtocolType(Decl *decl) {
if (!decl || decl->isInvalid())
return;
auto &ctx = decl->getASTContext();
if (auto *protocolDecl = dyn_cast<ProtocolDecl>(decl)) {
checkUnsupportedProtocolType(ctx, protocolDecl->getTrailingWhereClause());
} else if (auto *genericDecl = dyn_cast<GenericTypeDecl>(decl)) {
checkUnsupportedProtocolType(ctx, genericDecl->getGenericParams());
checkUnsupportedProtocolType(ctx, genericDecl->getTrailingWhereClause());
} else if (auto *assocType = dyn_cast<AssociatedTypeDecl>(decl)) {
checkUnsupportedProtocolType(ctx, assocType->getTrailingWhereClause());
} else if (auto *extDecl = dyn_cast<ExtensionDecl>(decl)) {
checkUnsupportedProtocolType(ctx, extDecl->getTrailingWhereClause());
} else if (auto *subscriptDecl = dyn_cast<SubscriptDecl>(decl)) {
checkUnsupportedProtocolType(ctx, subscriptDecl->getGenericParams());
checkUnsupportedProtocolType(ctx, subscriptDecl->getTrailingWhereClause());
} else if (auto *funcDecl = dyn_cast<AbstractFunctionDecl>(decl)) {
if (!isa<AccessorDecl>(funcDecl)) {
checkUnsupportedProtocolType(ctx, funcDecl->getGenericParams());
checkUnsupportedProtocolType(ctx, funcDecl->getTrailingWhereClause());
}
}
if (isa<TypeDecl>(decl) || isa<ExtensionDecl>(decl))
return;
UnsupportedProtocolVisitor visitor(ctx, /*checkStatements=*/false);
decl->walk(visitor);
}
void TypeChecker::checkUnsupportedProtocolType(ASTContext &ctx, Stmt *stmt) {
if (!stmt)
return;
UnsupportedProtocolVisitor visitor(ctx, /*checkStatements=*/true);
stmt->walk(visitor);
}
void TypeChecker::checkUnsupportedProtocolType(
ASTContext &ctx, TrailingWhereClause *whereClause) {
if (whereClause == nullptr)
return;
UnsupportedProtocolVisitor visitor(ctx, /*checkStatements=*/false);
visitor.visitRequirements(whereClause->getRequirements());
}
void TypeChecker::checkUnsupportedProtocolType(
ASTContext &ctx, GenericParamList *genericParams) {
if (genericParams == nullptr)
return;
UnsupportedProtocolVisitor visitor(ctx, /*checkStatements=*/false);
visitor.visitRequirements(genericParams->getRequirements());
}
Type CustomAttrTypeRequest::evaluate(Evaluator &eval, CustomAttr *attr,
DeclContext *dc,
CustomAttrTypeKind typeKind) const {
const TypeResolutionOptions options(TypeResolverContext::PatternBindingDecl);
OpenUnboundGenericTypeFn unboundTyOpener = nullptr;
// Property delegates allow their type to be an unbound generic.
if (typeKind == CustomAttrTypeKind::PropertyWrapper) {
unboundTyOpener = [](auto unboundTy) {
// FIXME: Don't let unbound generic types
// escape type resolution. For now, just
// return the unbound generic type.
return unboundTy;
};
}
ASTContext &ctx = dc->getASTContext();
const auto type = TypeResolution::forContextual(dc, options, unboundTyOpener)
.resolveType(attr->getTypeRepr());
// We always require the type to resolve to a nominal type.
if (!type->getAnyNominal()) {
assert(ctx.Diags.hadAnyError());
return ErrorType::get(ctx);
}
return type;
}