diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 4d2f154994e..2381f392bd1 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -1671,8 +1671,10 @@ ProtocolConformanceRef ModuleDecl::lookupConformance(Type type, if (auto nominal = type->getAnyNominal()) { ImplicitKnownProtocolConformanceRequest icvRequest{nominal, *kp}; if (getASTContext().evaluator.hasActiveRequest(icvRequest) || - getASTContext().evaluator.hasActiveRequest(request)) + getASTContext().evaluator.hasActiveRequest(request)) { + assert(!getInvertibleProtocolKind(*kp)); return ProtocolConformanceRef::forInvalid(); + } } } @@ -1731,13 +1733,35 @@ static ProtocolConformanceRef getBuiltinTupleTypeConformance( return ProtocolConformanceRef::forMissingOrInvalid(type, protocol); } +using EitherFunctionType = + llvm::PointerUnion; + /// Whether the given function type conforms to Sendable. -static bool isSendableFunctionType(const FunctionType *functionType) { - if (functionType->isSendable()) - return true; +static bool isSendableFunctionType(EitherFunctionType eitherFnTy) { + FunctionTypeRepresentation representation; + + if (auto silFnTy = eitherFnTy.dyn_cast()) { + if (silFnTy->isSendable()) + return true; + + // convert SILFunctionTypeRepresentation -> FunctionTypeRepresentation + auto converted = convertRepresentation(silFnTy->getRepresentation()); + if (!converted) + return false; + + representation = *converted; + + } else { + auto functionType = eitherFnTy.get(); + + if (functionType->isSendable()) + return true; + + representation = functionType->getExtInfo().getRepresentation(); + } // C and thin function types have no captures, so they are Sendable. - switch (functionType->getExtInfo().getRepresentation()) { + switch (representation) { case FunctionTypeRepresentation::Block: case FunctionTypeRepresentation::Swift: return false; @@ -1749,41 +1773,47 @@ static bool isSendableFunctionType(const FunctionType *functionType) { } /// Whether the given function type conforms to Escapable. -static bool isEscapableFunctionType(const FunctionType *functionType) { - if (functionType->isNoEscape()) - return false; +static bool isEscapableFunctionType(EitherFunctionType eitherFnTy) { + if (auto silFnTy = eitherFnTy.dyn_cast()) { + return !silFnTy->isNoEscape(); + } - // FIXME: do we need to also include autoclosures?? + auto functionType = eitherFnTy.get(); - return true; + // TODO: what about autoclosures? + return !functionType->isNoEscape(); } /// Synthesize a builtin function type conformance to the given protocol, if /// appropriate. static ProtocolConformanceRef getBuiltinFunctionTypeConformance( - Type type, const FunctionType *functionType, ProtocolDecl *protocol) { + Type type, EitherFunctionType functionType, ProtocolDecl *protocol) { ASTContext &ctx = protocol->getASTContext(); - // @Sendable function types are Sendable. - if (protocol->isSpecificProtocol(KnownProtocolKind::Sendable) && - isSendableFunctionType(functionType)) { - return ProtocolConformanceRef( - ctx.getBuiltinConformance(type, protocol, - BuiltinConformanceKind::Synthesized)); - } - // Functions cannot permanently destroy a move-only var/let - // that they capture, so it's safe to copy functions, like classes. - if (protocol->isSpecificProtocol(KnownProtocolKind::Copyable)) { + auto synthesizeConformance = [&]() -> ProtocolConformanceRef { return ProtocolConformanceRef( ctx.getBuiltinConformance(type, protocol, BuiltinConformanceKind::Synthesized)); - } + }; - if (protocol->isSpecificProtocol(KnownProtocolKind::Escapable) && - isEscapableFunctionType(functionType)) { - return ProtocolConformanceRef( - ctx.getBuiltinConformance(type, protocol, - BuiltinConformanceKind::Synthesized)); + if (auto kp = protocol->getKnownProtocolKind()) { + switch (*kp) { + case KnownProtocolKind::Escapable: + if (isEscapableFunctionType(functionType)) + return synthesizeConformance(); + break; + case KnownProtocolKind::Sendable: + // @Sendable function types are Sendable. + if (isSendableFunctionType(functionType)) + return synthesizeConformance(); + break; + case KnownProtocolKind::Copyable: + // Functions cannot permanently destroy a move-only var/let + // that they capture, so it's safe to copy functions, like classes. + return synthesizeConformance(); + default: + break; + } } return ProtocolConformanceRef::forMissingOrInvalid(type, protocol); @@ -1959,6 +1989,11 @@ LookupConformanceInModuleRequest::evaluate( return getBuiltinFunctionTypeConformance(type, functionType, protocol); } + // SIL function types in the AST can conform to protocols + if (auto silFn = type->getAs()) { + return getBuiltinFunctionTypeConformance(type, silFn, protocol); + } + // Metatypes can conform to protocols. if (auto metatypeType = type->getAs()) { return getBuiltinMetaTypeTypeConformance(type, metatypeType, protocol); @@ -1969,6 +2004,18 @@ LookupConformanceInModuleRequest::evaluate( return getBuiltinBuiltinTypeConformance(type, builtinType, protocol); } +#ifndef NDEBUG + // Ensure we haven't missed queries for the specialty SIL types + // in the AST in conformance to one of the invertible protocols. + if (auto kp = protocol->getKnownProtocolKind()) + if (getInvertibleProtocolKind(*kp)) + assert(!(type->is())); +#endif + auto nominal = type->getAnyNominal(); // If we don't have a nominal type, there are no conformances. diff --git a/lib/SIL/IR/TypeLowering.cpp b/lib/SIL/IR/TypeLowering.cpp index 6d5551f3089..de84964764b 100644 --- a/lib/SIL/IR/TypeLowering.cpp +++ b/lib/SIL/IR/TypeLowering.cpp @@ -116,15 +116,16 @@ CaptureKind TypeConverter::getDeclCaptureKind(CapturedValue capture, assert(var->hasStorage() && "should not have attempted to directly capture this variable"); + auto contextTy = var->getTypeInContext(); auto &lowering = getTypeLowering( - var->getTypeInContext(), TypeExpansionContext::noOpaqueTypeArchetypesSubstitution( + contextTy, TypeExpansionContext::noOpaqueTypeArchetypesSubstitution( expansion.getResilienceExpansion())); // If this is a noncopyable 'let' constant that is not a shared paramdecl or // used by a noescape capture, then we know it is boxed and want to pass it in // its boxed form so we can obey Swift's capture reference semantics. if (!var->supportsMutation() - && lowering.getLoweredType().getASTType()->isNoncopyable() + && contextTy->isNoncopyable() && !capture.isNoEscape()) { auto *param = dyn_cast(var); if (!param || (param->getValueOwnership() != ValueOwnership::Shared && diff --git a/lib/Sema/TypeCheckInvertible.cpp b/lib/Sema/TypeCheckInvertible.cpp index 3b7ca686117..7931f7049b9 100644 --- a/lib/Sema/TypeCheckInvertible.cpp +++ b/lib/Sema/TypeCheckInvertible.cpp @@ -159,17 +159,28 @@ static void tryEmitContainmentFixits(InFlightDiagnostic &&diag, /// MARK: conformance queries static bool conformsToInvertible(CanType type, InvertibleProtocolKind ip) { - assert(!type->hasTypeParameter() && "forgot to mapTypeIntoContext first"); auto &ctx = type->getASTContext(); + auto *invertible = ctx.getProtocol(getKnownProtocolKind(ip)); + assert(invertible); + // Pack expansions such as `repeat T` themselves do not have conformances, // so check its pattern type for conformance. if (auto *pet = type->getAs()) { type = pet->getPatternType()->getCanonicalType(); } - auto *invertible = ctx.getProtocol(getKnownProtocolKind(ip)); - assert(invertible); + // Must either not have a type parameter, or in the case of a + // BoundGenericXType, have a nominal available. + assert(!type->hasTypeParameter() || type.getAnyNominal() + && "caller forgot to mapTypeIntoContext!"); + + // The SIL types in the AST do not have real conformances, and should have + // been handled earlier. + assert(!(type->is())); const bool conforms = (bool)TypeChecker::conformsToProtocol(type,