mirror of
https://github.com/apple/swift.git
synced 2026-02-27 18:26:24 +01:00
Use pattern substitutions to consistently abstract yields.
The design implemented in this patch is that we lower the types of accessors with pattern substitutions when lowering them against a different accessor, which happens with class overrides and protocol witnesses, and that we introduce pattern substitutions when substituting into a non-patterned coroutine type. This seems to achieve consistent abstraction without introduce a ton of new complexity. An earlier version of this patch tried to define witness thunks (conservatively, just for accessors) by simply applying the requirement substitutions directly to the requirement. Conceptually that should work, but I ran into a lot of trouble with things that assumed that pattern substitutions didn't conceal significant substitution work. for example, resolving a dependent member in a component type could find a new use of an opaque archetype when the code assumed that such types had already been substituted away. So while I think that is definiteely a promising direction, I had to back that out in order to make the number of changes manageable for a single PR. As part of this, I had to fix a number of little bugs here and there, some of which I just introduced. One of these bugfixes is a place where the substitution code was trying to improperly abstract function types when substituting them in for a type parameter, and it's been in the code for a really long time, and I'm really not sure how it's never blown up before. I'm increasingly of the opinion that invocation substitutions are not actually necessary, but that --- after we've solved the substitution issues above --- we may want the ability to build multiple levels of pattern substitution so that we can guarantee that e.g. witness thunks always have the exact component structure of the requirement before a certain level of substitution, thus allowing the witness substitutions to be easily extracted.
This commit is contained in:
391
include/swift/AST/TypeDifferenceVisitor.h
Normal file
391
include/swift/AST/TypeDifferenceVisitor.h
Normal file
@@ -0,0 +1,391 @@
|
||||
//===--- TypeDifferenceVisitor.h - Visitor for pairs of types ---*- C++ -*-===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See https://swift.org/LICENSE.txt for license information
|
||||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines TypeDifferenceVisitor, a visitor which finds
|
||||
// differences between canonical types.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SWIFT_AST_TYPEDIFFERENCEVISITOR_H
|
||||
#define SWIFT_AST_TYPEDIFFERENCEVISITOR_H
|
||||
|
||||
#include "swift/AST/SILLayout.h"
|
||||
#include "swift/AST/Types.h"
|
||||
|
||||
namespace swift {
|
||||
|
||||
// TODO: maybe have a version of this that works on non-canonical types
|
||||
|
||||
template <class Impl, class RetTy, class... Args>
|
||||
class CanTypePairVisitor {
|
||||
public:
|
||||
// Provide default implementations that chain to the base class.
|
||||
#define ABSTRACT_TYPE(CLASS, PARENT) \
|
||||
RetTy visit##CLASS##Type(Can##CLASS##Type type1, \
|
||||
Can##CLASS##Type type2, \
|
||||
Args... args) { \
|
||||
return static_cast<Impl&>(*this) \
|
||||
.visit##PARENT(type1, type2, std::forward<Args>(args)...); \
|
||||
}
|
||||
#define TYPE(CLASS, PARENT) ABSTRACT_TYPE(CLASS, PARENT)
|
||||
#define ABSTRACT_SUGARED_TYPE(CLASS, PARENT)
|
||||
#define SUGARED_TYPE(CLASS, PARENT)
|
||||
// Don't allow unchecked types by default, but allow visitors to opt-in to
|
||||
// handling them.
|
||||
#define UNCHECKED_TYPE(CLASS, PARENT) \
|
||||
RetTy visit##CLASS##Type(Can##CLASS##Type type1, \
|
||||
Can##CLASS##Type type2, \
|
||||
Args... args) { \
|
||||
llvm_unreachable("unchecked type"); \
|
||||
}
|
||||
#include "swift/AST/TypeNodes.def"
|
||||
};
|
||||
|
||||
/// A CRTP class for finding differences between types.
|
||||
///
|
||||
/// The visitors all short-circuit as soon as one returns true.
|
||||
///
|
||||
/// visitDifferentTypes()
|
||||
template <class Impl>
|
||||
class CanTypeDifferenceVisitor : public CanTypePairVisitor<Impl, bool> {
|
||||
protected:
|
||||
Impl &asImpl() { return static_cast<Impl&>(*this); }
|
||||
public:
|
||||
/// Two component types differ.
|
||||
bool visitDifferentComponentTypes(CanType type1, CanType type2) {
|
||||
asImpl().visitDifferentTypes(type1, type2);
|
||||
|
||||
// Short-circuit by default.
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Two types differ in non-type structure, like a convention or a label.
|
||||
/// Generally, you can't usefully recover when this is called; it always
|
||||
/// needs to return true.
|
||||
bool visitDifferentTypeStructure(CanType type1, CanType type2) {
|
||||
asImpl().visitDifferentTypes(type1, type2);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Inform the subclass that a difference was detected.
|
||||
void visitDifferentTypes(CanType type1, CanType type2) {}
|
||||
|
||||
bool visit(CanType type1, CanType type2) {
|
||||
if (type1 == type2)
|
||||
return false;
|
||||
|
||||
if (type1->getKind() != type2->getKind())
|
||||
return asImpl().visitDifferentComponentTypes(type1, type2);
|
||||
|
||||
switch (type1->getKind()) {
|
||||
#define SUGARED_TYPE(CLASS, PARENT) \
|
||||
case TypeKind::CLASS:
|
||||
#define TYPE(CLASS, PARENT)
|
||||
#include "swift/AST/TypeNodes.def"
|
||||
llvm_unreachable("non-canonical type");
|
||||
|
||||
#define SUGARED_TYPE(CLASS, PARENT)
|
||||
#define TYPE(CLASS, PARENT) \
|
||||
case TypeKind::CLASS: \
|
||||
return asImpl().visit##CLASS##Type(cast<CLASS##Type>(type1), \
|
||||
cast<CLASS##Type>(type2));
|
||||
#include "swift/AST/TypeNodes.def"
|
||||
}
|
||||
llvm_unreachable("Not reachable, all cases handled");
|
||||
}
|
||||
|
||||
// In the type-specific visitors, we know that we have
|
||||
// non-identical types.
|
||||
|
||||
// These types are singleton and can't actually differ.
|
||||
#define SINGLETON_TYPE(TYPE) \
|
||||
bool visit##TYPE(Can##TYPE type1, Can##TYPE type2) { \
|
||||
llvm_unreachable("singleton type that wasn't identical"); \
|
||||
}
|
||||
SINGLETON_TYPE(BuiltinIntegerLiteralType)
|
||||
SINGLETON_TYPE(BuiltinRawPointerType)
|
||||
SINGLETON_TYPE(BuiltinNativeObjectType)
|
||||
SINGLETON_TYPE(BuiltinBridgeObjectType)
|
||||
SINGLETON_TYPE(BuiltinUnsafeValueBufferType)
|
||||
SINGLETON_TYPE(SILTokenType)
|
||||
#undef SINGLETON_TYPE
|
||||
|
||||
bool visitBuiltinIntegerType(CanBuiltinIntegerType type1,
|
||||
CanBuiltinIntegerType type2) {
|
||||
return asImpl().visitDifferentTypeStructure(type1, type2);
|
||||
}
|
||||
|
||||
bool visitBuiltinFloatType(CanBuiltinFloatType type1,
|
||||
CanBuiltinFloatType type2) {
|
||||
return asImpl().visitDifferentTypeStructure(type1, type2);
|
||||
}
|
||||
|
||||
bool visitBuiltinVectorType(CanBuiltinVectorType type1,
|
||||
CanBuiltinVectorType type2) {
|
||||
if (type1->getNumElements() != type2->getNumElements())
|
||||
return asImpl().visitDifferentTypeStructure(type1, type2);
|
||||
return asImpl().visit(type1.getElementType(), type2.getElementType());
|
||||
}
|
||||
|
||||
bool visitTupleType(CanTupleType type1, CanTupleType type2) {
|
||||
return visitComponentArray(type1, type2,
|
||||
type1->getElements(), type2->getElements());
|
||||
}
|
||||
|
||||
bool visitComponent(CanType type1, CanType type2,
|
||||
const TupleTypeElt &elt1, const TupleTypeElt &elt2) {
|
||||
if (elt1.getName() != elt2.getName())
|
||||
return asImpl().visitDifferentTypeStructure(type1, type2);
|
||||
return asImpl().visit(CanType(elt1.getType()), CanType(elt2.getType()));
|
||||
}
|
||||
|
||||
bool visitReferenceStorageType(CanReferenceStorageType type1,
|
||||
CanReferenceStorageType type2) {
|
||||
return asImpl().visit(type1.getReferentType(), type2.getReferentType());
|
||||
}
|
||||
|
||||
bool visitUnboundGenericType(CanUnboundGenericType type1,
|
||||
CanUnboundGenericType type2) {
|
||||
assert(type1->getDecl() != type2->getDecl());
|
||||
return asImpl().visitDifferentTypeStructure(type1, type2);
|
||||
}
|
||||
|
||||
bool visitNominalType(CanNominalType type1, CanNominalType type2) {
|
||||
assert(type1->getDecl() != type2->getDecl());
|
||||
return asImpl().visitDifferentTypeStructure(type1, type2);
|
||||
}
|
||||
|
||||
bool visitBoundGenericType(CanBoundGenericType type1,
|
||||
CanBoundGenericType type2) {
|
||||
if (type1->getDecl() != type2->getDecl())
|
||||
return asImpl().visitDifferentTypeStructure(type1, type2);
|
||||
|
||||
return visitComponentArray(type1, type2,
|
||||
type1.getGenericArgs(), type2.getGenericArgs());
|
||||
}
|
||||
|
||||
bool visitAnyMetatypeType(CanAnyMetatypeType type1,
|
||||
CanAnyMetatypeType type2) {
|
||||
if (type1->hasRepresentation() != type2->hasRepresentation() ||
|
||||
(type1->hasRepresentation() &&
|
||||
type1->getRepresentation() != type2->getRepresentation()))
|
||||
return asImpl().visitDifferentTypeStructure(type1, type2);
|
||||
|
||||
return asImpl().visit(type1.getInstanceType(), type2.getInstanceType());
|
||||
}
|
||||
|
||||
bool visitModuleType(CanModuleType type1, CanModuleType type2) {
|
||||
return asImpl().visitDifferentTypeStructure(type1, type2);
|
||||
}
|
||||
|
||||
bool visitDynamicSelfType(CanDynamicSelfType type1,
|
||||
CanDynamicSelfType type2) {
|
||||
return asImpl().visit(type1.getSelfType(), type2.getSelfType());
|
||||
}
|
||||
|
||||
bool visitSubstitutableType(CanSubstitutableType type1,
|
||||
CanSubstitutableType type2) {
|
||||
return asImpl().visitDifferentComponentTypes(type1, type2);
|
||||
}
|
||||
|
||||
bool visitDependentMemberType(CanDependentMemberType type1,
|
||||
CanDependentMemberType type2) {
|
||||
if (type1->getName() != type2->getName())
|
||||
return asImpl().visitDifferentTypeStructure(type1, type2);
|
||||
return asImpl().visit(type1.getBase(), type2.getBase());
|
||||
}
|
||||
|
||||
bool visitGenericFunctionType(CanGenericFunctionType type1,
|
||||
CanGenericFunctionType type2) {
|
||||
if (type1.getGenericSignature() != type2.getGenericSignature())
|
||||
return asImpl().visitDifferentTypeStructure(type1, type2);
|
||||
|
||||
return asImpl().visitAnyFunctionType(type1, type2);
|
||||
}
|
||||
|
||||
bool visitAnyFunctionType(CanAnyFunctionType type1,
|
||||
CanAnyFunctionType type2) {
|
||||
if (type1->getExtInfo() != type2->getExtInfo())
|
||||
return asImpl().visitDifferentTypeStructure(type1, type2);
|
||||
|
||||
if (asImpl().visit(type1.getResult(), type2.getResult()))
|
||||
return true;
|
||||
|
||||
return visitComponentArray(type1, type2,
|
||||
type1.getParams(), type2.getParams());
|
||||
}
|
||||
|
||||
bool visitComponent(CanType type1, CanType type2,
|
||||
AnyFunctionType::CanParam param1,
|
||||
AnyFunctionType::CanParam param2) {
|
||||
if (param1.getLabel() != param2.getLabel() ||
|
||||
param1.getParameterFlags() != param2.getParameterFlags())
|
||||
return asImpl().visitDifferentTypeStructure(type1, type2);
|
||||
return asImpl().visit(param1.getPlainType(), param2.getPlainType());
|
||||
}
|
||||
|
||||
bool visitSILFunctionType(CanSILFunctionType type1,
|
||||
CanSILFunctionType type2) {
|
||||
return (asImpl().visitSILFunctionTypeStructure(type1, type2) ||
|
||||
asImpl().visitSILFunctionTypeSubstitutions(type1, type2) ||
|
||||
asImpl().visitSILFunctionTypeComponents(type1, type2));
|
||||
}
|
||||
|
||||
bool visitSILFunctionTypeStructure(CanSILFunctionType type1,
|
||||
CanSILFunctionType type2) {
|
||||
if (type1->getExtInfo() != type2->getExtInfo() ||
|
||||
type1->getCoroutineKind() != type2->getCoroutineKind() ||
|
||||
type1->getInvocationGenericSignature()
|
||||
!= type2->getInvocationGenericSignature())
|
||||
return asImpl().visitDifferentTypeStructure(type1, type2);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visitSILFunctionTypeSubstitutions(CanSILFunctionType type1,
|
||||
CanSILFunctionType type2) {
|
||||
return asImpl().visitOptSubstitutionMap(type1, type2,
|
||||
type1->getPatternSubstitutions(),
|
||||
type2->getPatternSubstitutions())
|
||||
|| asImpl().visitOptSubstitutionMap(type1, type2,
|
||||
type1->getInvocationSubstitutions(),
|
||||
type2->getInvocationSubstitutions());
|
||||
}
|
||||
|
||||
bool visitSILFunctionTypeComponents(CanSILFunctionType type1,
|
||||
CanSILFunctionType type2) {
|
||||
return visitComponentArray(type1, type2,
|
||||
type1->getParameters(), type2->getParameters())
|
||||
|| visitComponentArray(type1, type2,
|
||||
type1->getResults(), type2->getResults())
|
||||
|| visitComponentArray(type1, type2,
|
||||
type1->getYields(), type2->getYields());
|
||||
}
|
||||
|
||||
bool visitComponent(CanType type1, CanType type2,
|
||||
SILParameterInfo param1, SILParameterInfo param2) {
|
||||
if (param1.getConvention() != param2.getConvention() ||
|
||||
param1.getDifferentiability() != param2.getDifferentiability())
|
||||
return asImpl().visitDifferentTypeStructure(type1, type2);
|
||||
|
||||
return asImpl().visit(param1.getInterfaceType(),
|
||||
param2.getInterfaceType());
|
||||
}
|
||||
|
||||
bool visitComponent(CanType type1, CanType type2,
|
||||
SILResultInfo result1, SILResultInfo result2) {
|
||||
if (result1.getConvention() != result2.getConvention())
|
||||
return asImpl().visitDifferentTypeStructure(type1, type2);
|
||||
|
||||
return asImpl().visit(result1.getInterfaceType(),
|
||||
result2.getInterfaceType());
|
||||
}
|
||||
|
||||
bool visitComponent(CanType type1, CanType type2,
|
||||
SILYieldInfo yield1, SILYieldInfo yield2) {
|
||||
if (yield1.getConvention() != yield2.getConvention())
|
||||
return asImpl().visitDifferentTypeStructure(type1, type2);
|
||||
|
||||
return asImpl().visit(yield1.getInterfaceType(),
|
||||
yield2.getInterfaceType());
|
||||
}
|
||||
|
||||
bool visitSILBoxType(CanSILBoxType type1, CanSILBoxType type2) {
|
||||
return (asImpl().visitSILLayout(type1, type2,
|
||||
type1->getLayout(), type2->getLayout()) ||
|
||||
asImpl().visitOptSubstitutionMap(type1, type2,
|
||||
type1->getSubstitutions(),
|
||||
type2->getSubstitutions()));
|
||||
}
|
||||
|
||||
bool visitSILLayout(CanType type1, CanType type2,
|
||||
SILLayout *layout1, SILLayout *layout2) {
|
||||
if (layout1->getGenericSignature() != layout2->getGenericSignature() ||
|
||||
layout1->isMutable() != layout2->isMutable())
|
||||
return asImpl().visitDifferentTypeStructure(type1, type2);
|
||||
|
||||
return visitComponentArray(type1, type2,
|
||||
layout1->getFields(), layout2->getFields());
|
||||
}
|
||||
|
||||
bool visitComponent(CanType type1, CanType type2,
|
||||
const SILField &field1, const SILField &field2) {
|
||||
if (field1.isMutable() != field2.isMutable())
|
||||
return asImpl().visitDifferentTypeStructure(type1, type2);
|
||||
return asImpl().visit(field1.getLoweredType(), field2.getLoweredType());
|
||||
}
|
||||
|
||||
bool visitSILBlockStorageType(CanSILBlockStorageType type1,
|
||||
CanSILBlockStorageType type2) {
|
||||
return asImpl().visit(type1->getCaptureType(), type2->getCaptureType());
|
||||
}
|
||||
|
||||
bool visitProtocolCompositionType(CanProtocolCompositionType type1,
|
||||
CanProtocolCompositionType type2) {
|
||||
return visitComponentArray(type1, type2,
|
||||
type1->getMembers(), type2->getMembers());
|
||||
}
|
||||
|
||||
bool visitLValueType(CanLValueType type1, CanLValueType type2) {
|
||||
return asImpl().visit(type1.getObjectType(), type2.getObjectType());
|
||||
}
|
||||
|
||||
bool visitInOutType(CanInOutType type1, CanInOutType type2) {
|
||||
return asImpl().visit(type1.getObjectType(), type2.getObjectType());
|
||||
}
|
||||
|
||||
bool visitErrorType(CanErrorType type1, CanErrorType type2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visitOptSubstitutionMap(CanType type1, CanType type2,
|
||||
SubstitutionMap subs1, SubstitutionMap subs2) {
|
||||
if ((bool) subs1 != (bool) subs2)
|
||||
return asImpl().visitDifferentTypeStructure(type1, type2);
|
||||
if (subs1)
|
||||
return asImpl().visitSubstitutionMap(type1, type2, subs1, subs2);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visitSubstitutionMap(CanType type1, CanType type2,
|
||||
SubstitutionMap subs1, SubstitutionMap subs2) {
|
||||
if (CanGenericSignature(subs1.getGenericSignature())
|
||||
!= CanGenericSignature(subs2.getGenericSignature()))
|
||||
return asImpl().visitDifferentTypeStructure(type1, type2);
|
||||
|
||||
return visitComponentArray(type1, type2,
|
||||
subs1.getReplacementTypes(),
|
||||
subs2.getReplacementTypes());
|
||||
}
|
||||
|
||||
private:
|
||||
bool visitComponent(CanType type1, CanType type2,
|
||||
Type componentType1, Type componentType2) {
|
||||
return asImpl().visit(CanType(componentType1), CanType(componentType2));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool visitComponentArray(CanType type1, CanType type2, T array1, T array2) {
|
||||
if (array1.size() != array2.size())
|
||||
return asImpl().visitDifferentTypeStructure(type1, type2);
|
||||
|
||||
for (auto i : indices(array1)) {
|
||||
if (asImpl().visitComponent(type1, type2, array1[i], array2[i]))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -4883,6 +4883,17 @@ public:
|
||||
CanSILFunctionType
|
||||
withPatternSubstitutions(SubstitutionMap subs) const;
|
||||
|
||||
/// Create a SILFunctionType with the same structure as this one,
|
||||
/// but replacing the invocation generic signature and pattern
|
||||
/// substitutions. This type must either be polymorphic or have
|
||||
/// pattern substitutions, and the substitution signature must
|
||||
/// match `getSubstGenericSignature()`.
|
||||
CanSILFunctionType
|
||||
withPatternSpecialization(CanGenericSignature sign,
|
||||
SubstitutionMap subs,
|
||||
ProtocolConformanceRef witnessConformance =
|
||||
ProtocolConformanceRef()) const;
|
||||
|
||||
class ABICompatibilityCheckResult {
|
||||
friend class SILFunctionType;
|
||||
|
||||
|
||||
@@ -354,6 +354,11 @@ public:
|
||||
return SILFunctionConventions(LoweredType, getModule());
|
||||
}
|
||||
|
||||
SILFunctionConventions getConventionsInContext() const {
|
||||
auto fnType = getLoweredFunctionTypeInContext(getTypeExpansionContext());
|
||||
return SILFunctionConventions(fnType, getModule());
|
||||
}
|
||||
|
||||
SILProfiler *getProfiler() const { return Profiler; }
|
||||
|
||||
SILFunction *getDynamicallyReplacedFunction() const {
|
||||
|
||||
@@ -380,6 +380,11 @@ public:
|
||||
bool hasArchetype() const {
|
||||
return getASTType()->hasArchetype();
|
||||
}
|
||||
|
||||
/// True if the type involves any opaque archetypes.
|
||||
bool hasOpaqueArchetype() const {
|
||||
return getASTType()->hasOpaqueArchetype();
|
||||
}
|
||||
|
||||
/// Returns the ASTContext for the referenced Swift type.
|
||||
ASTContext &getASTContext() const {
|
||||
|
||||
@@ -1511,6 +1511,9 @@ void ASTMangler::appendImplFunctionType(SILFunctionType *fn) {
|
||||
OpArgs.push_back('G');
|
||||
break;
|
||||
}
|
||||
|
||||
auto outerGenericSig = CurGenericSignature;
|
||||
CurGenericSignature = fn->getSubstGenericSignature();
|
||||
|
||||
// Mangle the parameters.
|
||||
for (auto param : fn->getParameters()) {
|
||||
@@ -1538,8 +1541,10 @@ void ASTMangler::appendImplFunctionType(SILFunctionType *fn) {
|
||||
OpArgs.push_back(getResultConvention(error.getConvention()));
|
||||
appendType(error.getInterfaceType());
|
||||
}
|
||||
|
||||
if (auto sig = fn->getInvocationGenericSignature()) {
|
||||
appendGenericSignature(sig);
|
||||
CurGenericSignature = outerGenericSig;
|
||||
}
|
||||
if (auto subs = fn->getInvocationSubstitutions()) {
|
||||
appendFlatGenericArgs(subs);
|
||||
@@ -1547,8 +1552,13 @@ void ASTMangler::appendImplFunctionType(SILFunctionType *fn) {
|
||||
}
|
||||
if (auto subs = fn->getPatternSubstitutions()) {
|
||||
appendGenericSignature(subs.getGenericSignature());
|
||||
CurGenericSignature =
|
||||
fn->getInvocationGenericSignature()
|
||||
? fn->getInvocationGenericSignature()
|
||||
: outerGenericSig;
|
||||
appendFlatGenericArgs(subs);
|
||||
appendRetroactiveConformances(subs, Mod);
|
||||
CurGenericSignature = outerGenericSig;
|
||||
}
|
||||
|
||||
OpArgs.push_back('_');
|
||||
|
||||
@@ -4208,10 +4208,8 @@ public:
|
||||
}
|
||||
sub->Printer << ") -> ";
|
||||
|
||||
unsigned totalResults =
|
||||
T->getNumYields() + T->getNumResults() + unsigned(T->hasErrorResult());
|
||||
|
||||
if (totalResults != 1)
|
||||
bool parenthesizeResults = mustParenthesizeResults(T);
|
||||
if (parenthesizeResults)
|
||||
sub->Printer << "(";
|
||||
|
||||
first = true;
|
||||
@@ -4235,7 +4233,7 @@ public:
|
||||
T->getErrorResult().getInterfaceType().print(sub->Printer, subOptions);
|
||||
}
|
||||
|
||||
if (totalResults != 1)
|
||||
if (parenthesizeResults)
|
||||
sub->Printer << ")";
|
||||
}();
|
||||
|
||||
@@ -4252,6 +4250,24 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
static bool mustParenthesizeResults(SILFunctionType *T) {
|
||||
// If we don't have exactly one result, we must parenthesize.
|
||||
unsigned totalResults =
|
||||
T->getNumYields() + T->getNumResults() + unsigned(T->hasErrorResult());
|
||||
if (totalResults != 1)
|
||||
return true;
|
||||
|
||||
// If we have substitutions, we must parenthesize if the single
|
||||
// result is a function type.
|
||||
if (!T->hasPatternSubstitutions() && !T->hasInvocationSubstitutions())
|
||||
return false;
|
||||
if (T->getNumResults() == 1)
|
||||
return isa<SILFunctionType>(T->getResults()[0].getInterfaceType());
|
||||
if (T->getNumYields() == 1)
|
||||
return isa<SILFunctionType>(T->getYields()[0].getInterfaceType());
|
||||
return isa<SILFunctionType>(T->getErrorResult().getInterfaceType());
|
||||
}
|
||||
|
||||
void visitSILBlockStorageType(SILBlockStorageType *T) {
|
||||
Printer << "@block_storage ";
|
||||
printWithParensIfNotSimple(T->getCaptureType());
|
||||
|
||||
@@ -5254,6 +5254,25 @@ SILFunctionType::withPatternSubstitutions(SubstitutionMap subs) const {
|
||||
getWitnessMethodConformanceOrInvalid());
|
||||
}
|
||||
|
||||
CanSILFunctionType
|
||||
SILFunctionType::withPatternSpecialization(CanGenericSignature sig,
|
||||
SubstitutionMap subs,
|
||||
ProtocolConformanceRef
|
||||
witnessConformance) const {
|
||||
assert(!hasInvocationSubstitutions());
|
||||
subs = subs.getCanonical();
|
||||
assert(!subs || CanGenericSignature(subs.getGenericSignature())
|
||||
== getSubstGenericSignature());
|
||||
return SILFunctionType::get(sig,
|
||||
getExtInfo(), getCoroutineKind(),
|
||||
getCalleeConvention(),
|
||||
getParameters(), getYields(), getResults(),
|
||||
getOptionalErrorResult(),
|
||||
subs, SubstitutionMap(),
|
||||
const_cast<SILFunctionType*>(this)->getASTContext(),
|
||||
witnessConformance);
|
||||
}
|
||||
|
||||
SourceLoc swift::extractNearestSourceLoc(Type ty) {
|
||||
if (auto nominal = ty->getAnyNominal())
|
||||
return extractNearestSourceLoc(nominal);
|
||||
|
||||
@@ -744,6 +744,7 @@ class SubstFunctionTypeCollector {
|
||||
public:
|
||||
TypeConverter &TC;
|
||||
TypeExpansionContext Expansion;
|
||||
CanGenericSignature GenericSig;
|
||||
bool Enabled;
|
||||
|
||||
SmallVector<GenericTypeParamType *, 4> substGenericParams;
|
||||
@@ -752,8 +753,8 @@ public:
|
||||
SmallVector<ProtocolConformanceRef, 4> substConformances;
|
||||
|
||||
SubstFunctionTypeCollector(TypeConverter &TC, TypeExpansionContext context,
|
||||
bool enabled)
|
||||
: TC(TC), Expansion(context), Enabled(enabled) {
|
||||
CanGenericSignature genericSig, bool enabled)
|
||||
: TC(TC), Expansion(context), GenericSig(genericSig), Enabled(enabled) {
|
||||
}
|
||||
SubstFunctionTypeCollector(const SubstFunctionTypeCollector &) = delete;
|
||||
|
||||
@@ -789,6 +790,7 @@ public:
|
||||
}
|
||||
|
||||
if (upperBoundSuperclass) {
|
||||
upperBoundSuperclass = upperBoundSuperclass->mapTypeOutOfContext();
|
||||
substRequirements.push_back(
|
||||
Requirement(RequirementKind::Superclass, param, upperBoundSuperclass));
|
||||
}
|
||||
@@ -875,11 +877,9 @@ public:
|
||||
|
||||
auto origContextType = origType.getType();
|
||||
|
||||
// TODO: If the substituted type is a subclass of the abstraction pattern
|
||||
// type, then bail out. This should only come up when lowering override
|
||||
// types for vtable entries, where we don't currently use substituted
|
||||
// function types.
|
||||
|
||||
// If the substituted type is a subclass of the abstraction pattern
|
||||
// type, build substitutions for any type parameters in it. This only
|
||||
// comes up when lowering override types for vtable entries.
|
||||
auto areDifferentClasses = [](Type a, Type b) -> bool {
|
||||
if (auto dynA = a->getAs<DynamicSelfType>()) {
|
||||
a = dynA->getSelfType();
|
||||
@@ -896,17 +896,24 @@ public:
|
||||
return false;
|
||||
};
|
||||
|
||||
bool substituteBindingsInSubstType = false;
|
||||
if (areDifferentClasses(substType, origContextType)) {
|
||||
return substType;
|
||||
substituteBindingsInSubstType = true;
|
||||
}
|
||||
if (auto substMeta = dyn_cast<MetatypeType>(substType)) {
|
||||
if (auto origMeta = dyn_cast<MetatypeType>(origContextType)) {
|
||||
if (areDifferentClasses(substMeta->getInstanceType(),
|
||||
origMeta->getInstanceType())) {
|
||||
return substType;
|
||||
substituteBindingsInSubstType = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CanGenericSignature origSig = origType.getGenericSignature();
|
||||
if (substituteBindingsInSubstType) {
|
||||
origContextType = substType;
|
||||
origSig = GenericSig;
|
||||
}
|
||||
|
||||
if (!origContextType->hasTypeParameter()
|
||||
&& !origContextType->hasArchetype()) {
|
||||
@@ -919,9 +926,9 @@ public:
|
||||
|
||||
// Extract structural substitutions.
|
||||
if (origContextType->hasTypeParameter())
|
||||
origContextType = origType.getGenericSignature()->getGenericEnvironment()
|
||||
origContextType = origSig->getGenericEnvironment()
|
||||
->mapTypeIntoContext(origContextType)
|
||||
->getCanonicalType(origType.getGenericSignature());
|
||||
->getCanonicalType(origSig);
|
||||
|
||||
auto result = origContextType
|
||||
->substituteBindingsTo(substType,
|
||||
@@ -1681,6 +1688,14 @@ static CanSILFunctionType getSILFunctionType(
|
||||
if (!TC.Context.LangOpts.EnableSubstSILFunctionTypesForFunctionValues)
|
||||
return false;
|
||||
|
||||
// We always use substituted function types for coroutines that are
|
||||
// being lowered in the context of another coroutine, which is to say,
|
||||
// for class override thunks. This is required to make the yields
|
||||
// match in abstraction to the base method's yields, which is necessary
|
||||
// to make the extracted continuation-function signatures match.
|
||||
if (constant != origConstant && getAsCoroutineAccessor(constant))
|
||||
return true;
|
||||
|
||||
// We don't currently use substituted function types for generic function
|
||||
// type lowering, though we should for generic methods on classes and
|
||||
// protocols.
|
||||
@@ -1696,7 +1711,7 @@ static CanSILFunctionType getSILFunctionType(
|
||||
rep == SILFunctionTypeRepresentation::Thin);
|
||||
}();
|
||||
|
||||
SubstFunctionTypeCollector subst(TC, expansionContext,
|
||||
SubstFunctionTypeCollector subst(TC, expansionContext, genericSig,
|
||||
shouldBuildSubstFunctionType);
|
||||
|
||||
// Destructure the input tuple type.
|
||||
@@ -3174,11 +3189,13 @@ public:
|
||||
//
|
||||
// There are two caveats here. The first is that we haven't yet
|
||||
// written all the code that would be necessary in order to handle
|
||||
// invocation substitutions everywhere, so we only build those if
|
||||
// there are pattern substitutions on a polymorphic type, which is
|
||||
// something that we only currently generate in narrow cases.
|
||||
// Instead we substitute the generic arguments into the components
|
||||
// and build a type with no invocation signature.
|
||||
// invocation substitutions everywhere, and so we never build those.
|
||||
// Instead, we substitute into the pattern substitutions if present,
|
||||
// or the components if not, and build a type with no invocation
|
||||
// signature. As a special case, when substituting a coroutine type,
|
||||
// we build pattern substitutions instead of substituting the
|
||||
// component types in order to preserve the original yield structure,
|
||||
// which factors into the continuation function ABI.
|
||||
//
|
||||
// The second is that this function is also used when substituting
|
||||
// opaque archetypes. In this case, we may need to substitute
|
||||
@@ -3214,30 +3231,42 @@ public:
|
||||
// Otherwise, we shouldn't substitute any components except
|
||||
// when substituting opaque archetypes.
|
||||
|
||||
// If we're doing a generic application, and there are pattern
|
||||
// substitutions, substitute into the pattern substitutions; or if
|
||||
// it's a coroutine, build pattern substitutions; or else, fall
|
||||
// through to substitute the component types as discussed above.
|
||||
if (isGenericApplication) {
|
||||
if (patternSubs || origType->isCoroutine()) {
|
||||
CanSILFunctionType substType = origType;
|
||||
if (typeExpansionContext.shouldLookThroughOpaqueTypeArchetypes()) {
|
||||
substType =
|
||||
origType->substituteOpaqueArchetypes(TC, typeExpansionContext);
|
||||
}
|
||||
|
||||
SubstitutionMap subs;
|
||||
if (patternSubs) {
|
||||
subs = substSubstitutions(patternSubs);
|
||||
} else {
|
||||
subs = SubstitutionMap::get(sig, Subst, Conformances);
|
||||
}
|
||||
auto witnessConformance = substWitnessConformance(origType);
|
||||
substType = substType->withPatternSpecialization(nullptr, subs,
|
||||
witnessConformance);
|
||||
|
||||
return substType;
|
||||
}
|
||||
// else fall down to component substitution
|
||||
|
||||
// If we're substituting opaque archetypes, and there are pattern
|
||||
// substitutions present, just substitute those and preserve the
|
||||
// basic structure in the component types. Otherwise, fall through
|
||||
// to substitute the component types.
|
||||
if (shouldSubstituteOpaqueArchetypes) {
|
||||
} else if (shouldSubstituteOpaqueArchetypes) {
|
||||
if (patternSubs) {
|
||||
patternSubs = substOpaqueTypes(patternSubs);
|
||||
return origType->withPatternSubstitutions(patternSubs);
|
||||
}
|
||||
// else fall down to component substitution
|
||||
|
||||
// If we're doing a generic application, and there are pattern
|
||||
// substitutions, build invocation substitutions and substitute
|
||||
// opaque types in the pattern subs. Otherwise, fall through
|
||||
// to substitue the component types as discussed above.
|
||||
} else if (isGenericApplication) {
|
||||
if (patternSubs) {
|
||||
patternSubs = substOpaqueTypes(patternSubs);
|
||||
auto substType = origType->withPatternSubstitutions(patternSubs);
|
||||
|
||||
auto invocationSubs = SubstitutionMap::get(sig, Subst, Conformances);
|
||||
substType = substType->withInvocationSubstitutions(invocationSubs);
|
||||
|
||||
return substType;
|
||||
auto witnessConformance = substWitnessConformance(origType);
|
||||
return origType->withPatternSpecialization(sig, patternSubs,
|
||||
witnessConformance);
|
||||
}
|
||||
// else fall down to component substitution
|
||||
|
||||
@@ -3246,7 +3275,9 @@ public:
|
||||
auto substType = origType;
|
||||
if (patternSubs) {
|
||||
patternSubs = substOpaqueTypes(patternSubs);
|
||||
substType = substType->withPatternSubstitutions(patternSubs);
|
||||
auto witnessConformance = substWitnessConformance(origType);
|
||||
substType = substType->withPatternSpecialization(sig, patternSubs,
|
||||
witnessConformance);
|
||||
}
|
||||
return substType;
|
||||
}
|
||||
@@ -3255,7 +3286,9 @@ public:
|
||||
// into those and don't touch the component types.
|
||||
} else if (patternSubs) {
|
||||
patternSubs = substSubstitutions(patternSubs);
|
||||
return origType->withPatternSubstitutions(patternSubs);
|
||||
auto witnessConformance = substWitnessConformance(origType);
|
||||
return origType->withPatternSpecialization(nullptr, patternSubs,
|
||||
witnessConformance);
|
||||
}
|
||||
|
||||
// Otherwise, we need to substitute component types.
|
||||
@@ -3283,34 +3316,7 @@ public:
|
||||
substYields.push_back(substInterface(origYield));
|
||||
}
|
||||
|
||||
ProtocolConformanceRef witnessMethodConformance;
|
||||
if (auto conformance = origType->getWitnessMethodConformanceOrInvalid()) {
|
||||
assert(origType->getExtInfo().hasSelfParam());
|
||||
auto selfType = origType->getSelfParameter().getInterfaceType();
|
||||
|
||||
// The Self type can be nested in a few layers of metatypes (etc.).
|
||||
while (auto metatypeType = dyn_cast<MetatypeType>(selfType)) {
|
||||
auto next = metatypeType.getInstanceType();
|
||||
if (next == selfType)
|
||||
break;
|
||||
selfType = next;
|
||||
}
|
||||
|
||||
witnessMethodConformance =
|
||||
conformance.subst(selfType, Subst, Conformances);
|
||||
|
||||
// Substitute the underlying conformance of opaque type archetypes if we
|
||||
// should look through opaque archetypes.
|
||||
if (typeExpansionContext.shouldLookThroughOpaqueTypeArchetypes()) {
|
||||
SubstOptions substOptions(None);
|
||||
auto substType = selfType.subst(Subst, Conformances, substOptions)
|
||||
->getCanonicalType();
|
||||
if (substType->hasOpaqueArchetype()) {
|
||||
witnessMethodConformance = substOpaqueTypesWithUnderlyingTypes(
|
||||
witnessMethodConformance, substType, typeExpansionContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
auto witnessMethodConformance = substWitnessConformance(origType);
|
||||
|
||||
// The substituted type is no longer generic, so it'd never be
|
||||
// pseudogeneric.
|
||||
@@ -3330,6 +3336,39 @@ public:
|
||||
TC.Context, witnessMethodConformance);
|
||||
}
|
||||
|
||||
ProtocolConformanceRef substWitnessConformance(CanSILFunctionType origType) {
|
||||
auto conformance = origType->getWitnessMethodConformanceOrInvalid();
|
||||
if (!conformance) return conformance;
|
||||
|
||||
assert(origType->getExtInfo().hasSelfParam());
|
||||
auto selfType = origType->getSelfParameter().getInterfaceType();
|
||||
|
||||
// The Self type can be nested in a few layers of metatypes (etc.).
|
||||
while (auto metatypeType = dyn_cast<MetatypeType>(selfType)) {
|
||||
auto next = metatypeType.getInstanceType();
|
||||
if (next == selfType)
|
||||
break;
|
||||
selfType = next;
|
||||
}
|
||||
|
||||
auto substConformance =
|
||||
conformance.subst(selfType, Subst, Conformances);
|
||||
|
||||
// Substitute the underlying conformance of opaque type archetypes if we
|
||||
// should look through opaque archetypes.
|
||||
if (typeExpansionContext.shouldLookThroughOpaqueTypeArchetypes()) {
|
||||
SubstOptions substOptions(None);
|
||||
auto substType = selfType.subst(Subst, Conformances, substOptions)
|
||||
->getCanonicalType();
|
||||
if (substType->hasOpaqueArchetype()) {
|
||||
substConformance = substOpaqueTypesWithUnderlyingTypes(
|
||||
substConformance, substType, typeExpansionContext);
|
||||
}
|
||||
}
|
||||
|
||||
return substConformance;
|
||||
}
|
||||
|
||||
SILType subst(SILType type) {
|
||||
return SILType::getPrimitiveType(visit(type.getASTType()),
|
||||
type.getCategory());
|
||||
@@ -3402,12 +3441,6 @@ public:
|
||||
}
|
||||
|
||||
AbstractionPattern abstraction(Sig, origType);
|
||||
// If we looked through an opaque archetype to a function type we need to
|
||||
// use the function type's abstraction.
|
||||
if (isa<OpaqueTypeArchetypeType>(origType) &&
|
||||
isa<AnyFunctionType>(substType))
|
||||
abstraction = AbstractionPattern(Sig, substType);
|
||||
|
||||
return TC.getLoweredRValueType(typeExpansionContext, abstraction,
|
||||
substType);
|
||||
}
|
||||
|
||||
@@ -848,7 +848,7 @@ public:
|
||||
|
||||
SILVerifier(const SILFunction &F, bool SingleFunction = true)
|
||||
: M(F.getModule().getSwiftModule()), F(F),
|
||||
fnConv(F.getLoweredFunctionType(), F.getModule()),
|
||||
fnConv(F.getConventionsInContext()),
|
||||
TC(F.getModule().Types), OpenedArchetypes(&F), Dominance(nullptr),
|
||||
InstNumbers(numInstsInFunction(F)),
|
||||
DEBlocks(&F), SingleFunction(SingleFunction) {
|
||||
@@ -1322,12 +1322,12 @@ public:
|
||||
}
|
||||
|
||||
if (subs.getGenericSignature()->getCanonicalSignature() !=
|
||||
fnTy->getSubstGenericSignature()->getCanonicalSignature()) {
|
||||
fnTy->getInvocationGenericSignature()->getCanonicalSignature()) {
|
||||
llvm::dbgs() << "substitution map's generic signature: ";
|
||||
subs.getGenericSignature()->print(llvm::dbgs());
|
||||
llvm::dbgs() << "\n";
|
||||
llvm::dbgs() << "callee's generic signature: ";
|
||||
fnTy->getSubstGenericSignature()->print(llvm::dbgs());
|
||||
fnTy->getInvocationGenericSignature()->print(llvm::dbgs());
|
||||
llvm::dbgs() << "\n";
|
||||
require(false,
|
||||
"Substitution map does not match callee in apply instruction");
|
||||
@@ -3980,9 +3980,7 @@ public:
|
||||
void checkThrowInst(ThrowInst *TI) {
|
||||
LLVM_DEBUG(TI->print(llvm::dbgs()));
|
||||
|
||||
CanSILFunctionType fnType =
|
||||
F.getLoweredFunctionTypeInContext(F.getTypeExpansionContext());
|
||||
require(fnType->hasErrorResult(),
|
||||
require(fnConv.funcTy->hasErrorResult(),
|
||||
"throw in function that doesn't have an error result");
|
||||
|
||||
SILType functionResultType =
|
||||
@@ -4005,14 +4003,11 @@ public:
|
||||
}
|
||||
|
||||
void checkYieldInst(YieldInst *YI) {
|
||||
CanSILFunctionType fnType =
|
||||
F.getLoweredFunctionTypeInContext(F.getTypeExpansionContext())
|
||||
->getUnsubstitutedType(F.getModule());
|
||||
require(fnType->isCoroutine(),
|
||||
require(fnConv.funcTy->isCoroutine(),
|
||||
"yield in non-coroutine function");
|
||||
|
||||
auto yieldedValues = YI->getYieldedValues();
|
||||
auto yieldInfos = fnType->getYields();
|
||||
auto yieldInfos = fnConv.funcTy->getYields();
|
||||
require(yieldedValues.size() == yieldInfos.size(),
|
||||
"wrong number of yielded values for function");
|
||||
for (auto i : indices(yieldedValues)) {
|
||||
@@ -4676,7 +4671,7 @@ public:
|
||||
|
||||
for (auto result : fnConv.getIndirectSILResults()) {
|
||||
assert(fnConv.isSILIndirect(result));
|
||||
check("result", fnConv.getSILType(result));
|
||||
check("indirect result", fnConv.getSILType(result));
|
||||
}
|
||||
for (auto param : F.getLoweredFunctionType()->getParameters()) {
|
||||
check("parameter", fnConv.getSILType(param));
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "swift/AST/Pattern.h"
|
||||
#include "swift/AST/PrettyStackTrace.h"
|
||||
#include "swift/AST/PropertyWrappers.h"
|
||||
#include "swift/AST/TypeDifferenceVisitor.h"
|
||||
#include "swift/AST/Types.h"
|
||||
#include "swift/ClangImporter/ClangModule.h"
|
||||
#include "swift/SIL/PrettyStackTrace.h"
|
||||
@@ -2537,6 +2538,63 @@ TypeConverter::checkForABIDifferences(SILModule &M,
|
||||
return ABIDifference::NeedsThunk;
|
||||
}
|
||||
|
||||
namespace {
|
||||
class HaveDifferentAbstractStructure
|
||||
: public CanTypeDifferenceVisitor<HaveDifferentAbstractStructure> {
|
||||
public:
|
||||
// Treat any sort of abstract type as equivalent.
|
||||
static bool isAbstract(CanType type) {
|
||||
return (isa<SubstitutableType>(type) || isa<DependentMemberType>(type));
|
||||
};
|
||||
|
||||
// We can fast-path some of these checks by proviing these two overrides:
|
||||
bool visitSubstitutableType(CanSubstitutableType type1,
|
||||
CanSubstitutableType type2) {
|
||||
return false;
|
||||
}
|
||||
bool visitDependentMemberType(CanDependentMemberType type1,
|
||||
CanDependentMemberType type2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We also need to handle the general case where we have different
|
||||
// kinds of substitutable types.
|
||||
bool visitDifferentComponentTypes(CanType type1, CanType type2) {
|
||||
// This is a difference only if both types aren't abstract.
|
||||
return !(isAbstract(type1) && isAbstract(type2));
|
||||
}
|
||||
|
||||
// Change the rules used for SIL function types to only consider
|
||||
// the basic structure, not any substitutions.
|
||||
bool visitSILFunctionType(CanSILFunctionType type1,
|
||||
CanSILFunctionType type2) {
|
||||
return visitSILFunctionTypeStructure(type1, type2)
|
||||
|| visitSILFunctionTypeComponents(type1, type2);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static bool haveDifferentAbstractStructure(CanType type1, CanType type2) {
|
||||
return HaveDifferentAbstractStructure().visit(type1, type2);
|
||||
}
|
||||
|
||||
static TypeConverter::ABIDifference
|
||||
checkForABIDifferencesInYield(TypeConverter &TC, SILModule &M,
|
||||
SILFunctionType *fnTy1, SILYieldInfo yield1,
|
||||
SILFunctionType *fnTy2, SILYieldInfo yield2) {
|
||||
// Require the interface types to have the same basic abstract
|
||||
// structure, ignoring any substitutions from the function type.
|
||||
// This structure is what determines the signature of the continuation
|
||||
// function.
|
||||
if (haveDifferentAbstractStructure(yield1.getInterfaceType(),
|
||||
yield2.getInterfaceType()))
|
||||
return TypeConverter::ABIDifference::NeedsThunk;
|
||||
|
||||
// Also make sure that the actual yield types match in ABI.
|
||||
return TC.checkForABIDifferences(M, yield1.getSILStorageType(M, fnTy1),
|
||||
yield2.getSILStorageType(M, fnTy2));
|
||||
}
|
||||
|
||||
TypeConverter::ABIDifference
|
||||
TypeConverter::checkFunctionForABIDifferences(SILModule &M,
|
||||
SILFunctionType *fnTy1,
|
||||
@@ -2596,10 +2654,7 @@ TypeConverter::checkFunctionForABIDifferences(SILModule &M,
|
||||
if (yield1.getConvention() != yield2.getConvention())
|
||||
return ABIDifference::NeedsThunk;
|
||||
|
||||
if (checkForABIDifferences(M,
|
||||
yield1.getSILStorageType(M, fnTy1),
|
||||
yield2.getSILStorageType(M, fnTy2),
|
||||
/*thunk iuos*/ fnTy1->getLanguage() == SILFunctionLanguage::Swift)
|
||||
if (checkForABIDifferencesInYield(*this, M, fnTy1, yield1, fnTy2, yield2)
|
||||
!= ABIDifference::CompatibleRepresentation)
|
||||
return ABIDifference::NeedsThunk;
|
||||
}
|
||||
|
||||
@@ -870,14 +870,16 @@ namespace {
|
||||
SILLocation Loc;
|
||||
ArrayRef<ManagedValue> Inputs;
|
||||
SmallVectorImpl<ManagedValue> &Outputs;
|
||||
CanSILFunctionType OutputTypesFuncTy;
|
||||
ArrayRef<SILParameterInfo> OutputTypes;
|
||||
public:
|
||||
TranslateArguments(SILGenFunction &SGF, SILLocation loc,
|
||||
ArrayRef<ManagedValue> inputs,
|
||||
SmallVectorImpl<ManagedValue> &outputs,
|
||||
CanSILFunctionType outputTypesFuncTy,
|
||||
ArrayRef<SILParameterInfo> outputTypes)
|
||||
: SGF(SGF), Loc(loc), Inputs(inputs), Outputs(outputs),
|
||||
OutputTypes(outputTypes) {}
|
||||
OutputTypesFuncTy(outputTypesFuncTy), OutputTypes(outputTypes) {}
|
||||
|
||||
void translate(AbstractionPattern inputOrigFunctionType,
|
||||
AnyFunctionType::CanParamArrayRef inputSubstTypes,
|
||||
@@ -1045,7 +1047,7 @@ namespace {
|
||||
"Output is not a tuple and is not opaque?");
|
||||
|
||||
auto outputTy = SGF.getSILType(claimNextOutputType(),
|
||||
CanSILFunctionType());
|
||||
OutputTypesFuncTy);
|
||||
auto &outputTL = SGF.getTypeLowering(outputTy);
|
||||
if (SGF.silConv.useLoweredAddresses()) {
|
||||
auto temp = SGF.emitTemporary(Loc, outputTL);
|
||||
@@ -1166,7 +1168,7 @@ namespace {
|
||||
auto &loweredTL = SGF.getTypeLowering(outputOrigType, outputTupleType);
|
||||
auto loweredTy = loweredTL.getLoweredType();
|
||||
auto optionalTy = SGF.getSILType(claimNextOutputType(),
|
||||
CanSILFunctionType());
|
||||
OutputTypesFuncTy);
|
||||
auto someDecl = SGF.getASTContext().getOptionalSomeDecl();
|
||||
if (loweredTL.isLoadable() || !SGF.silConv.useLoweredAddresses()) {
|
||||
auto payload =
|
||||
@@ -1422,8 +1424,9 @@ namespace {
|
||||
CanType outputSubstType,
|
||||
ManagedValue input,
|
||||
SILParameterInfo result) {
|
||||
auto resultTy = SGF.getSILType(result, OutputTypesFuncTy);
|
||||
// Easy case: we want to pass exactly this value.
|
||||
if (input.getType() == SGF.getSILType(result, CanSILFunctionType())) {
|
||||
if (input.getType() == resultTy) {
|
||||
switch (result.getConvention()) {
|
||||
case ParameterConvention::Direct_Owned:
|
||||
case ParameterConvention::Indirect_In:
|
||||
@@ -1446,8 +1449,7 @@ namespace {
|
||||
case ParameterConvention::Direct_Unowned:
|
||||
translateIntoOwned(inputOrigType, inputSubstType, outputOrigType,
|
||||
outputSubstType, input);
|
||||
assert(Outputs.back().getType() == SGF.getSILType(result,
|
||||
CanSILFunctionType()));
|
||||
assert(Outputs.back().getType() == resultTy);
|
||||
return;
|
||||
case ParameterConvention::Direct_Guaranteed:
|
||||
translateIntoGuaranteed(inputOrigType, inputSubstType, outputOrigType,
|
||||
@@ -1456,27 +1458,23 @@ namespace {
|
||||
case ParameterConvention::Indirect_In: {
|
||||
if (SGF.silConv.useLoweredAddresses()) {
|
||||
translateIndirect(inputOrigType, inputSubstType, outputOrigType,
|
||||
outputSubstType, input,
|
||||
SGF.getSILType(result, CanSILFunctionType()));
|
||||
outputSubstType, input, resultTy);
|
||||
return;
|
||||
}
|
||||
translateIntoOwned(inputOrigType, inputSubstType, outputOrigType,
|
||||
outputSubstType, input);
|
||||
assert(Outputs.back().getType() ==
|
||||
SGF.getSILType(result, CanSILFunctionType()));
|
||||
assert(Outputs.back().getType() == resultTy);
|
||||
return;
|
||||
}
|
||||
case ParameterConvention::Indirect_In_Guaranteed: {
|
||||
if (SGF.silConv.useLoweredAddresses()) {
|
||||
translateIndirect(inputOrigType, inputSubstType, outputOrigType,
|
||||
outputSubstType, input,
|
||||
SGF.getSILType(result, CanSILFunctionType()));
|
||||
outputSubstType, input, resultTy);
|
||||
return;
|
||||
}
|
||||
translateIntoGuaranteed(inputOrigType, inputSubstType, outputOrigType,
|
||||
outputSubstType, input);
|
||||
assert(Outputs.back().getType() ==
|
||||
SGF.getSILType(result, CanSILFunctionType()));
|
||||
assert(Outputs.back().getType() == resultTy);
|
||||
return;
|
||||
}
|
||||
case ParameterConvention::Indirect_Inout:
|
||||
@@ -1497,14 +1495,15 @@ namespace {
|
||||
CanType outputSubstType,
|
||||
ManagedValue input,
|
||||
SILParameterInfo result) {
|
||||
auto resultTy = SGF.getSILType(result, OutputTypesFuncTy);
|
||||
assert(input.isLValue());
|
||||
if (input.getType() == SGF.getSILType(result, CanSILFunctionType())) {
|
||||
if (input.getType() == resultTy) {
|
||||
Outputs.push_back(input);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a temporary of the right type.
|
||||
auto &temporaryTL = SGF.getTypeLowering(result.getInterfaceType());
|
||||
auto &temporaryTL = SGF.getTypeLowering(resultTy);
|
||||
auto temporary = SGF.emitTemporary(Loc, temporaryTL);
|
||||
|
||||
// Take ownership of the input value. This leaves the input l-value
|
||||
@@ -1742,6 +1741,7 @@ static void translateYields(SILGenFunction &SGF, SILLocation loc,
|
||||
// Translate the yields as if they were arguments.
|
||||
SmallVector<ManagedValue, 4> outerMVs;
|
||||
TranslateArguments translator(SGF, loc, innerMVs, outerMVs,
|
||||
CanSILFunctionType(),
|
||||
outerLoweredTypesAsParameters);
|
||||
|
||||
translator.translate(innerInfos.getOrigTypes(), innerInfos.getSubstTypes(),
|
||||
@@ -2911,7 +2911,7 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc,
|
||||
// other direction (the thunk receives an Int like a T, and passes it
|
||||
// like a normal Int when calling the inner function).
|
||||
SmallVector<ManagedValue, 8> args;
|
||||
TranslateArguments(SGF, loc, params, args, argTypes)
|
||||
TranslateArguments(SGF, loc, params, args, fnType, argTypes)
|
||||
.translate(outputOrigType,
|
||||
outputSubstType.getParams(),
|
||||
inputOrigType,
|
||||
@@ -2973,7 +2973,8 @@ buildThunkSignature(SILGenFunction &SGF,
|
||||
// If there's no opened existential, we just inherit the generic environment
|
||||
// from the parent function.
|
||||
if (openedExistential == nullptr) {
|
||||
auto genericSig = SGF.F.getLoweredFunctionType()->getSubstGenericSignature();
|
||||
auto genericSig =
|
||||
SGF.F.getLoweredFunctionType()->getInvocationGenericSignature();
|
||||
genericEnv = SGF.F.getGenericEnvironment();
|
||||
interfaceSubs = SGF.F.getForwardingSubstitutionMap();
|
||||
contextSubs = interfaceSubs;
|
||||
@@ -2984,7 +2985,8 @@ buildThunkSignature(SILGenFunction &SGF,
|
||||
int depth = 0;
|
||||
GenericSignature baseGenericSig;
|
||||
if (inheritGenericSig) {
|
||||
if (auto genericSig = SGF.F.getLoweredFunctionType()->getSubstGenericSignature()) {
|
||||
if (auto genericSig =
|
||||
SGF.F.getLoweredFunctionType()->getInvocationGenericSignature()) {
|
||||
baseGenericSig = genericSig;
|
||||
depth = genericSig->getGenericParams().back()->getDepth() + 1;
|
||||
}
|
||||
@@ -3008,7 +3010,7 @@ buildThunkSignature(SILGenFunction &SGF,
|
||||
// Calculate substitutions to map the caller's archetypes to the thunk's
|
||||
// archetypes.
|
||||
if (auto calleeGenericSig = SGF.F.getLoweredFunctionType()
|
||||
->getSubstGenericSignature()) {
|
||||
->getInvocationGenericSignature()) {
|
||||
contextSubs = SubstitutionMap::get(
|
||||
calleeGenericSig,
|
||||
[&](SubstitutableType *type) -> Type {
|
||||
@@ -3666,7 +3668,7 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
|
||||
}
|
||||
|
||||
auto subs = getForwardingSubstitutionMap();
|
||||
if (auto genericSig = derivedFTy->getSubstGenericSignature()) {
|
||||
if (auto genericSig = derivedFTy->getInvocationGenericSignature()) {
|
||||
subs = SubstitutionMap::get(genericSig, subs);
|
||||
|
||||
derivedFTy =
|
||||
@@ -3689,7 +3691,7 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
|
||||
|
||||
// Reabstract the arguments.
|
||||
TranslateArguments(*this, loc, thunkArgs, substArgs,
|
||||
derivedFTy->getParameters())
|
||||
derivedFTy, derivedFTy->getParameters())
|
||||
.translate(inputOrigType,
|
||||
inputSubstType.getParams(),
|
||||
outputOrigType,
|
||||
@@ -3989,7 +3991,7 @@ void SILGenFunction::emitProtocolWitness(AbstractionPattern reqtOrigTy,
|
||||
AbstractionPattern witnessOrigTy(witnessInfo.LoweredType);
|
||||
TranslateArguments(*this, loc,
|
||||
origParams, witnessParams,
|
||||
witnessUnsubstTy->getParameters())
|
||||
witnessUnsubstTy, witnessUnsubstTy->getParameters())
|
||||
.translate(reqtOrigTy,
|
||||
reqtSubstParams,
|
||||
witnessOrigTy,
|
||||
|
||||
@@ -797,6 +797,7 @@ createSpecializedType(CanSILFunctionType SubstFTy, SILModule &M) const {
|
||||
|
||||
unsigned IndirectResultIdx = 0;
|
||||
for (SILResultInfo RI : SubstFTy->getResults()) {
|
||||
RI = RI.getUnsubstituted(M, SubstFTy);
|
||||
if (RI.isFormalIndirect()) {
|
||||
bool isTrivial = TrivialArgs.test(IndirectResultIdx);
|
||||
if (isFormalResultConverted(IndirectResultIdx++)) {
|
||||
@@ -806,7 +807,7 @@ createSpecializedType(CanSILFunctionType SubstFTy, SILModule &M) const {
|
||||
auto C = (isTrivial
|
||||
? ResultConvention::Unowned
|
||||
: ResultConvention::Owned);
|
||||
SpecializedResults.push_back(SILResultInfo(RI.getReturnValueType(M, SubstFTy), C));
|
||||
SpecializedResults.push_back(RI.getWithConvention(C));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -815,6 +816,7 @@ createSpecializedType(CanSILFunctionType SubstFTy, SILModule &M) const {
|
||||
}
|
||||
unsigned ParamIdx = 0;
|
||||
for (SILParameterInfo PI : SubstFTy->getParameters()) {
|
||||
PI = PI.getUnsubstituted(M, SubstFTy);
|
||||
bool isTrivial = TrivialArgs.test(param2ArgIndex(ParamIdx));
|
||||
if (!isParamConverted(ParamIdx++)) {
|
||||
// No conversion: re-use the original, substituted parameter info.
|
||||
@@ -834,11 +836,11 @@ createSpecializedType(CanSILFunctionType SubstFTy, SILModule &M) const {
|
||||
C = ParameterConvention::Direct_Owned;
|
||||
}
|
||||
}
|
||||
SpecializedParams.push_back(SILParameterInfo(PI.getArgumentType(M, SubstFTy), C));
|
||||
SpecializedParams.push_back(PI.getWithConvention(C));
|
||||
}
|
||||
for (SILYieldInfo YI : SubstFTy->getYields()) {
|
||||
// For now, always just use the original, substituted parameter info.
|
||||
SpecializedYields.push_back(YI);
|
||||
// For now, always re-use the original, substituted yield info.
|
||||
SpecializedYields.push_back(YI.getUnsubstituted(M, SubstFTy));
|
||||
}
|
||||
|
||||
auto Signature = SubstFTy->isPolymorphic()
|
||||
|
||||
@@ -2962,6 +2962,8 @@ Type TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr,
|
||||
return ErrorType::get(Context);
|
||||
|
||||
Type selfType = params.back().getInterfaceType();
|
||||
if (patternSubs)
|
||||
selfType = selfType.subst(patternSubs);
|
||||
if (invocationSubs) {
|
||||
selfType = selfType.subst(invocationSubs);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ struct X : P {}
|
||||
var a = X()
|
||||
(a~>bar)(())
|
||||
|
||||
// CHECK: [[CHAINED_FUNC:%.*]] = apply {{%.*}}<X, (), ()>({{%.*}}, {{%.*}}) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : P> (@inout τ_0_0, @noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> (@inout τ_0_0) -> @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <τ_0_1, τ_0_2> for <τ_0_0, τ_0_1, τ_0_2>) -> @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <τ_0_1, τ_0_2>
|
||||
// CHECK: [[CHAINED_FUNC:%.*]] = apply {{%.*}}<X, (), ()>({{%.*}}, {{%.*}}) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : P> (@inout τ_0_0, @noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> (@inout τ_0_0) -> (@owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <τ_0_1, τ_0_2>) for <τ_0_0, τ_0_1, τ_0_2>) -> @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <τ_0_1, τ_0_2>
|
||||
// CHECK: [[CHAINED_FUNC_CONV:%.*]] = convert_function [[CHAINED_FUNC]] : $@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <(), ()> to $@callee_guaranteed (@in_guaranteed ()) -> @out ()
|
||||
// CHECK: [[REABSTRACT:%.*]] = function_ref @$sytytIegnr_Ieg_TR
|
||||
// CHECK: [[CHAINED_FUNC_REABSTRACTED:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACT]]([[CHAINED_FUNC_CONV]])
|
||||
|
||||
122
test/SILGen/coroutine_subst_function_types.swift
Normal file
122
test/SILGen/coroutine_subst_function_types.swift
Normal file
@@ -0,0 +1,122 @@
|
||||
// RUN: %target-swift-emit-silgen -module-name mod %s | %FileCheck %s
|
||||
|
||||
class Generic<T> {
|
||||
init() { preconditionFailure("death") }
|
||||
|
||||
// CHECK-LABEL: sil hidden [transparent] [ossa] @$s3mod7GenericC7genericxvM : $@yield_once @convention(method) <T> (@guaranteed Generic<T>) -> @yields @inout T
|
||||
var generic: T
|
||||
|
||||
// CHECK-LABEL: sil hidden [transparent] [ossa] @$s3mod7GenericC15genericFunctionxycvM : $@yield_once @convention(method) <T> (@guaranteed Generic<T>) -> @yields @inout @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <T>
|
||||
var genericFunction: () -> T
|
||||
|
||||
// CHECK-LABEL: sil hidden [transparent] [ossa] @$s3mod7GenericC09returningB0xqd___tcluiM : $@yield_once @convention(method) <T><U> (@in_guaranteed U, @guaranteed Generic<T>) -> @yields @inout T
|
||||
subscript<U>(returningGeneric i: U) -> T {
|
||||
get { return generic }
|
||||
set {}
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil hidden [transparent] [ossa] @$s3mod7GenericC012returningOwnB0qd__qd___tcluiM : $@yield_once @convention(method) <T><U> (@in_guaranteed U, @guaranteed Generic<T>) -> @yields @inout U {
|
||||
subscript<U>(returningOwnGeneric i: U) -> U {
|
||||
get { return i }
|
||||
set {}
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil hidden [transparent] [ossa] @$s3mod7GenericC12complexTuplexSg_SDySSxGtvM : $@yield_once @convention(method) <T> (@guaranteed Generic<T>) -> @yields @inout (Optional<T>, Dictionary<String, T>)
|
||||
var complexTuple: (T?, [String: T])
|
||||
}
|
||||
|
||||
class ConcreteWithInt: Generic<Int> {
|
||||
override init() { preconditionFailure("death") }
|
||||
|
||||
// The concrete implementations. Not actually important.
|
||||
// CHECK-LABEL: sil hidden [transparent] [ossa] @$s3mod15ConcreteWithIntC7genericSivM : $@yield_once @convention(method) (@guaranteed ConcreteWithInt) -> @yields @inout Int
|
||||
// CHECK-LABEL: sil hidden [transparent] [ossa] @$s3mod15ConcreteWithIntC15genericFunctionSiycvM : $@yield_once @convention(method) (@guaranteed ConcreteWithInt) -> @yields @inout @callee_guaranteed () -> Int
|
||||
// CHECK-LABEL: sil hidden [transparent] [ossa] @$s3mod15ConcreteWithIntC16returningGenericSix_tcluiM : $@yield_once @convention(method) <U> (@in_guaranteed U, @guaranteed ConcreteWithInt) -> @yields @inout Int
|
||||
// CHECK-LABEL: sil hidden [transparent] [ossa] @$s3mod15ConcreteWithIntC19returningOwnGenericxx_tcluiM : $@yield_once @convention(method) <U> (@in_guaranteed U, @guaranteed ConcreteWithInt) -> @yields @inout U
|
||||
// CHECK-LABEL: sil hidden [transparent] [ossa] @$s3mod15ConcreteWithIntC12complexTupleSiSg_SDySSSiGtvM : $@yield_once @convention(method) (@guaranteed ConcreteWithInt) -> @yields @inout (Optional<Int>, Dictionary<String, Int>)
|
||||
|
||||
// The override thunks. Note that the yields all exactly match the
|
||||
// original methods above in terms of where archetypes / type parameters
|
||||
// appear.
|
||||
|
||||
// CHECK-LABEL: sil private [thunk] [ossa] @$s3mod15ConcreteWithIntC7genericSivMAA7GenericCADxvMTV : $@yield_once @convention(method) @substituted <τ_0_0> (@guaranteed ConcreteWithInt) -> @yields @inout τ_0_0 for <Int>
|
||||
override var generic: Int {
|
||||
get { super.generic }
|
||||
set {}
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil private [thunk] [ossa] @$s3mod15ConcreteWithIntC15genericFunctionSiycvMAA7GenericCADxycvMTV : $@yield_once @convention(method) @substituted <τ_0_0> (@guaranteed ConcreteWithInt) -> (@yields @inout @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <τ_0_0>) for <Int>
|
||||
override var genericFunction: () -> Int {
|
||||
get { super.genericFunction }
|
||||
set {}
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil private [thunk] [ossa] @$s3mod15ConcreteWithIntC16returningGenericSix_tcluiMAA0F0CADxqd___tcluiMTV : $@yield_once @convention(method) <τ_0_0> @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0, @guaranteed ConcreteWithInt) -> @yields @inout τ_0_1 for <τ_0_0, Int>
|
||||
override subscript<U>(returningGeneric i: U) -> Int {
|
||||
get { return 0 }
|
||||
set {}
|
||||
}
|
||||
|
||||
// This one doesn't need a thunk.
|
||||
override subscript<U>(returningOwnGeneric i: U) -> U {
|
||||
get { return i }
|
||||
set {}
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil private [thunk] [ossa] @$s3mod15ConcreteWithIntC12complexTupleSiSg_SDySSSiGtvMAA7GenericCADxSg_SDySSxGtvMTV : $@yield_once @convention(method) @substituted <τ_0_0, τ_0_1> (@guaranteed ConcreteWithInt) -> @yields @inout (Optional<τ_0_0>, Dictionary<String, τ_0_1>) for <Int, Int>
|
||||
override var complexTuple: (Int?, [String: Int]) {
|
||||
get { super.complexTuple }
|
||||
set {}
|
||||
}
|
||||
}
|
||||
|
||||
protocol ProtoWithAssoc {
|
||||
associatedtype Assoc
|
||||
|
||||
@_borrowed
|
||||
var generic: Assoc { get set }
|
||||
|
||||
@_borrowed
|
||||
var genericFunction: () -> Assoc { get set }
|
||||
|
||||
@_borrowed
|
||||
subscript<U>(returningGeneric i: U) -> Assoc { get set }
|
||||
|
||||
@_borrowed
|
||||
subscript<U>(returningOwnGeneric i: U) -> U { get set }
|
||||
|
||||
@_borrowed
|
||||
var complexTuple: (Assoc?, [String: Assoc]) { get set }
|
||||
}
|
||||
extension ConcreteWithInt : ProtoWithAssoc {
|
||||
// The unsubstituted yields here should match the natural
|
||||
// abstractions for the protocol.
|
||||
|
||||
// var generic
|
||||
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s3mod15ConcreteWithIntCAA05ProtoC5AssocA2aDP7generic0F0QzvrTW : $@yield_once @convention(witness_method: ProtoWithAssoc) @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @yields @in_guaranteed τ_0_1 for <ConcreteWithInt, Int>
|
||||
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s3mod15ConcreteWithIntCAA05ProtoC5AssocA2aDP7generic0F0QzvMTW : $@yield_once @convention(witness_method: ProtoWithAssoc) @substituted <τ_0_0, τ_0_1> (@inout τ_0_0) -> @yields @inout τ_0_1 for <ConcreteWithInt, Int>
|
||||
|
||||
// var genericFunction
|
||||
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s3mod15ConcreteWithIntCAA05ProtoC5AssocA2aDP15genericFunction0F0QzycvrTW : $@yield_once @convention(witness_method: ProtoWithAssoc) @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> (@yields @guaranteed @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <τ_0_1>) for <ConcreteWithInt, Int>
|
||||
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s3mod15ConcreteWithIntCAA05ProtoC5AssocA2aDP15genericFunction0F0QzycvMTW : $@yield_once @convention(witness_method: ProtoWithAssoc) @substituted <τ_0_0, τ_0_1> (@inout τ_0_0) -> (@yields @inout @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <τ_0_1>) for <ConcreteWithInt, Int>
|
||||
|
||||
// subscript(returningGeneric:)
|
||||
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s3mod15ConcreteWithIntCAA05ProtoC5AssocA2aDP16returningGeneric0F0Qzqd___tcluirTW : $@yield_once @convention(witness_method: ProtoWithAssoc) <τ_0_0> @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_1) -> @yields @in_guaranteed τ_0_2 for <τ_0_0, ConcreteWithInt, Int>
|
||||
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s3mod15ConcreteWithIntCAA05ProtoC5AssocA2aDP16returningGeneric0F0Qzqd___tcluiMTW : $@yield_once @convention(witness_method: ProtoWithAssoc) <τ_0_0> @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0, @inout τ_0_1) -> @yields @inout τ_0_2 for <τ_0_0, ConcreteWithInt, Int>
|
||||
|
||||
// subscript(returningOwnGeneric:)
|
||||
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s3mod15ConcreteWithIntCAA05ProtoC5AssocA2aDP19returningOwnGenericqd__qd___tcluirTW : $@yield_once @convention(witness_method: ProtoWithAssoc) <τ_0_0> @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_1) -> @yields @in_guaranteed τ_0_2 for <τ_0_0, ConcreteWithInt, τ_0_0>
|
||||
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s3mod15ConcreteWithIntCAA05ProtoC5AssocA2aDP19returningOwnGenericqd__qd___tcluiMTW : $@yield_once @convention(witness_method: ProtoWithAssoc) <τ_0_0> @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0, @inout τ_0_1) -> @yields @inout τ_0_2 for <τ_0_0, ConcreteWithInt, τ_0_0>
|
||||
|
||||
// var complexTuple
|
||||
// CHECK-LABEL: sil shared [ossa] @$s3mod15ConcreteWithIntC12complexTupleSiSg_SDySSSiGtvr : $@yield_once @convention(method) (@guaranteed ConcreteWithInt) -> (@yields Optional<Int>, @yields @guaranteed Dictionary<String, Int>)
|
||||
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s3mod15ConcreteWithIntCAA05ProtoC5AssocA2aDP12complexTuple0F0QzSg_SDySSAHGtvMTW : $@yield_once @convention(witness_method: ProtoWithAssoc) @substituted <τ_0_0, τ_0_1, τ_0_2> (@inout τ_0_0) -> @yields @inout (Optional<τ_0_1>, Dictionary<String, τ_0_2>) for <ConcreteWithInt, Int, Int>
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil_vtable ConcreteWithInt {
|
||||
// CHECK: #Generic.generic!modify.1: <T> (Generic<T>) -> () -> () : @$s3mod15ConcreteWithIntC7genericSivMAA7GenericCADxvMTV [override]
|
||||
// CHECK: #Generic.genericFunction!modify.1: <T> (Generic<T>) -> () -> () : @$s3mod15ConcreteWithIntC15genericFunctionSiycvMAA7GenericCADxycvMTV [override]
|
||||
// CHECK: #Generic.subscript!modify.1: <T><U> (Generic<T>) -> (U) -> () : @$s3mod15ConcreteWithIntC16returningGenericSix_tcluiMAA0F0CADxqd___tcluiMTV [override]
|
||||
// CHECK: #Generic.subscript!modify.1: <T><U> (Generic<T>) -> (U) -> () : @$s3mod15ConcreteWithIntC19returningOwnGenericxx_tcluiM [override]
|
||||
// CHECK: #Generic.complexTuple!modify.1: <T> (Generic<T>) -> () -> () : @$s3mod15ConcreteWithIntC12complexTupleSiSg_SDySSSiGtvMAA7GenericCADxSg_SDySSxGtvMTV [override]
|
||||
// CHECK: }
|
||||
@@ -16,7 +16,7 @@ func c<T, U, V>(_ x: (V) -> T, _: U) {}
|
||||
// CHECK-LABEL: sil {{.*}}003Hca{{.*}} : $@convention(thin) <T> (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <T, T>) -> ()
|
||||
func ç<T>(_ x: (T) -> T) {}
|
||||
|
||||
// CHECK-LABEL: sil {{.*}}returnsThrowing{{.*}} : $@convention(thin) <T, U, V> (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0) -> @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> (@out τ_0_1, @error Error) for <τ_0_1, τ_0_2> for <T, U, V>) -> ()
|
||||
// CHECK-LABEL: sil {{.*}}returnsThrowing{{.*}} : $@convention(thin) <T, U, V> (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0) -> (@owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> (@out τ_0_1, @error Error) for <τ_0_1, τ_0_2>) for <T, U, V>) -> () {
|
||||
func returnsThrowing<T, U, V>(_ x: (T) -> (U) throws -> V) {}
|
||||
|
||||
|
||||
@@ -156,9 +156,10 @@ func z<T: P>(_: (SP<T>) -> Void) {}
|
||||
|
||||
struct SCP<T: P, U: CP<T>> {}
|
||||
|
||||
// CHECK-LABEL: sil {{.*}}2z2{{.*}} : $@convention(thin) <T, U where T : P, U : CP<T>> (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_0 : P, τ_0_1 : CP<T>, τ_0_1 : _NativeClass> (SCP<τ_0_0, τ_0_1>) -> () for <T, U>) -> ()
|
||||
// CHECK-LABEL: sil {{.*}}2z2{{.*}} : $@convention(thin) <T, U where T : P, U : CP<T>> (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_0 : P, τ_0_1 : CP<τ_0_0>, τ_0_1 : _NativeClass> (SCP<τ_0_0, τ_0_1>) -> () for <T, U>) -> ()
|
||||
func z2<T: P, U: CP<T>>(_: (SCP<T, U>) -> Void) {}
|
||||
// CHECK-LABEL: sil {{.*}}3z2a{{.*}} : $@convention(thin) <T, U where T : AnyObject, T : P, U : CP<T>> (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject, τ_0_0 : P, τ_0_1 : CP<T>, τ_0_1 : _NativeClass> (SCP<τ_0_0, τ_0_1>) -> () for <T, U>) -> ()
|
||||
|
||||
// CHECK-LABEL: sil {{.*}}3z2a{{.*}} : $@convention(thin) <T, U where T : AnyObject, T : P, U : CP<T>> (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject, τ_0_0 : P, τ_0_1 : CP<τ_0_0>, τ_0_1 : _NativeClass> (SCP<τ_0_0, τ_0_1>) -> () for <T, U>) -> ()
|
||||
func z2a<T: P & AnyObject, U: CP<T>>(_: (SCP<T, U>) -> Void) {}
|
||||
|
||||
// CHECK-LABEL: sil {{.*}}2z3{{.*}} : $@convention(thin) <T, U where T : P, U : CP<T>> (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject, τ_0_1 : _RefCountedObject> (S<τ_0_0, τ_0_1>) -> () for <U, U>) -> ()
|
||||
|
||||
@@ -52,4 +52,4 @@ class HasComputedProperty: ProtocolWithProperty {
|
||||
}
|
||||
}
|
||||
// CHECK-LABEL: sil hidden [transparent] [ossa] @$s10multi_file19HasComputedPropertyC3fooSivM : $@yield_once @convention(method) (@guaranteed HasComputedProperty) -> @yields @inout Int {
|
||||
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s10multi_file19HasComputedPropertyCAA012ProtocolWithE0A2aDP3fooSivMTW : $@yield_once @convention(witness_method: ProtocolWithProperty) (@inout HasComputedProperty) -> @yields @inout Int {
|
||||
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s10multi_file19HasComputedPropertyCAA012ProtocolWithE0A2aDP3fooSivMTW : $@yield_once @convention(witness_method: ProtocolWithProperty) @substituted <τ_0_0> (@inout τ_0_0) -> @yields @inout Int for <HasComputedProperty> {
|
||||
|
||||
Reference in New Issue
Block a user