Skip to content

PackElementType changes, part 2 #66294

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jun 2, 2023
Merged
12 changes: 1 addition & 11 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -6414,7 +6414,7 @@ class PackArchetypeType final
LayoutConstraint Layout);

// Returns the reduced shape type for this pack archetype.
CanType getReducedShape() const;
CanType getReducedShape();

static bool classof(const TypeBase *T) {
return T->getKind() == TypeKind::PackArchetype;
Expand Down Expand Up @@ -7098,16 +7098,6 @@ inline bool TypeBase::isTypeParameter() {
return t->is<GenericTypeParamType>();
}

inline bool TypeBase::isParameterPack() {
Type t(this);

while (auto *memberTy = t->getAs<DependentMemberType>())
t = memberTy->getBase();

return t->is<GenericTypeParamType>() &&
t->castTo<GenericTypeParamType>()->isParameterPack();
}

// TODO: This will become redundant once InOutType is removed.
inline bool TypeBase::isMaterializable() {
return !(hasLValueType() || is<InOutType>());
Expand Down
4 changes: 2 additions & 2 deletions include/swift/SIL/SILType.h
Original file line number Diff line number Diff line change
Expand Up @@ -686,12 +686,12 @@ class SILType {
SILType subst(Lowering::TypeConverter &tc, TypeSubstitutionFn subs,
LookupConformanceFn conformances,
CanGenericSignature genericSig = CanGenericSignature(),
bool shouldSubstituteOpaqueArchetypes = false) const;
SubstOptions options = None) const;

SILType subst(SILModule &M, TypeSubstitutionFn subs,
LookupConformanceFn conformances,
CanGenericSignature genericSig = CanGenericSignature(),
bool shouldSubstituteOpaqueArchetypes = false) const;
SubstOptions options = None) const;

SILType subst(Lowering::TypeConverter &tc,
InFlightSubstitution &IFS,
Expand Down
49 changes: 42 additions & 7 deletions lib/AST/ParameterPack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,18 @@ namespace {
/// skipping those captured by nested pack expansion types.
struct PackTypeParameterCollector: TypeWalker {
llvm::SetVector<Type> typeParams;
unsigned expansionLevel;
SmallVector<unsigned, 2> elementLevel;

PackTypeParameterCollector() : expansionLevel(0) {
elementLevel.push_back(0);
}

Action walkToTypePre(Type t) override {
if (t->is<PackExpansionType>())
return Action::SkipChildren;
if (t->is<PackExpansionType>()) {
++expansionLevel;
return Action::Continue;
}

if (auto *boundGenericType = dyn_cast<BoundGenericType>(t.getPointer())) {
if (auto parentType = boundGenericType->getParent())
Expand All @@ -58,13 +66,30 @@ struct PackTypeParameterCollector: TypeWalker {
}
}

if (auto *paramTy = t->getAs<GenericTypeParamType>()) {
if (paramTy->isParameterPack())
typeParams.insert(paramTy);
} else if (auto *archetypeTy = t->getAs<PackArchetypeType>()) {
typeParams.insert(archetypeTy->getRoot());
if (auto *eltType = t->getAs<PackElementType>()) {
elementLevel.push_back(eltType->getLevel());
return Action::Continue;
}

if (elementLevel.back() == expansionLevel) {
if (auto *paramTy = t->getAs<GenericTypeParamType>()) {
if (paramTy->isParameterPack())
typeParams.insert(paramTy);
} else if (auto *archetypeTy = t->getAs<PackArchetypeType>()) {
typeParams.insert(archetypeTy->getRoot());
}
}

return Action::Continue;
}

Action walkToTypePost(Type t) override {
if (t->is<PackExpansionType>())
--expansionLevel;

if (t->is<PackElementType>())
elementLevel.pop_back();

return Action::Continue;
}
};
Expand All @@ -90,6 +115,16 @@ bool GenericTypeParamType::isParameterPack() const {
GenericTypeParamType::TYPE_SEQUENCE_BIT;
}

bool TypeBase::isParameterPack() {
Type t(this);

while (auto *memberTy = t->getAs<DependentMemberType>())
t = memberTy->getBase();

return t->is<GenericTypeParamType>() &&
t->castTo<GenericTypeParamType>()->isParameterPack();
}

PackType *TypeBase::getPackSubstitutionAsPackType() {
if (auto pack = getAs<PackType>()) {
return pack;
Expand Down
7 changes: 2 additions & 5 deletions lib/AST/SubstitutionMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,16 +192,13 @@ SubstitutionMap SubstitutionMap::getCanonical(bool canonicalizeSignature) const

SubstitutionMap SubstitutionMap::get(GenericSignature genericSig,
SubstitutionMap substitutions) {
if (!genericSig) {
assert(!substitutions.hasAnySubstitutableParams() &&
"Shouldn't have substitutions here");
if (!genericSig)
return SubstitutionMap();
}

return SubstitutionMap::get(genericSig,
[&](SubstitutableType *type) -> Type {
return substitutions.lookupSubstitution(
CanSubstitutableType(type));
cast<SubstitutableType>(type->getCanonicalType()));
},
LookUpConformanceInSubstitutionMap(substitutions));
}
Expand Down
13 changes: 11 additions & 2 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3734,9 +3734,18 @@ PackArchetypeType::get(const ASTContext &Ctx,
{ShapeType}));
}

CanType PackArchetypeType::getReducedShape() const {
CanType PackArchetypeType::getReducedShape() {
// mapTypeIntoContext() also calls getReducedShape() via
// PackExpansionType::get(), so avoid that by short-circuiting
// the case where the pack archetype represents its own
// shape class.
auto shapeType = getTrailingObjects<PackShape>()->shapeType;
return getGenericEnvironment()->mapTypeIntoContext(shapeType)->getCanonicalType();
if (shapeType->isEqual(getInterfaceType()))
return CanType(this);

return getGenericEnvironment()
->mapTypeIntoContext(shapeType)
->getCanonicalType();
}

ElementArchetypeType::ElementArchetypeType(
Expand Down
2 changes: 1 addition & 1 deletion lib/IRGen/MetadataRequest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ SILType IRGenModule::substOpaqueTypesWithUnderlyingTypes(
getSILModule().isWholeModule());
auto underlyingTy =
type.subst(getSILModule(), replacer, replacer, genericSig,
/*substitute opaque*/ true);
SubstFlags::SubstituteOpaqueArchetypes);
return underlyingTy;
}

Expand Down
6 changes: 4 additions & 2 deletions lib/SIL/IR/SILFunctionType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4571,13 +4571,15 @@ static bool areABICompatibleParamsOrReturns(SILType a, SILType b,
inFunction->getModule().isWholeModule());
if (aa.getASTType()->hasOpaqueArchetype())
opaqueTypesSubstituted = aa.subst(inFunction->getModule(), replacer,
replacer, CanGenericSignature(), true);
replacer, CanGenericSignature(),
SubstFlags::SubstituteOpaqueArchetypes);

auto opaqueTypesSubstituted2 = bb;
if (bb.getASTType()->hasOpaqueArchetype())
opaqueTypesSubstituted2 =
bb.subst(inFunction->getModule(), replacer, replacer,
CanGenericSignature(), true);
CanGenericSignature(),
SubstFlags::SubstituteOpaqueArchetypes);
if (opaqueTypesSubstituted == opaqueTypesSubstituted2)
continue;
}
Expand Down
25 changes: 9 additions & 16 deletions lib/SIL/IR/SILTypeSubstitution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -465,35 +465,29 @@ class SILTypeSubstituter :

} // end anonymous namespace

static bool isSubstitutionInvariant(SILType ty,
bool shouldSubstituteOpaqueArchetypes) {
static bool isSubstitutionInvariant(SILType ty, SubstOptions options) {
return (!ty.hasArchetype() &&
!ty.hasTypeParameter() &&
(!shouldSubstituteOpaqueArchetypes ||
(!options.contains(SubstFlags::SubstituteOpaqueArchetypes) ||
!ty.getRawASTType()->hasOpaqueArchetype()));
}

SILType SILType::subst(TypeConverter &tc, TypeSubstitutionFn subs,
LookupConformanceFn conformances,
CanGenericSignature genericSig,
bool shouldSubstituteOpaqueArchetypes) const {
if (isSubstitutionInvariant(*this, shouldSubstituteOpaqueArchetypes))
SubstOptions options) const {
if (isSubstitutionInvariant(*this, options))
return *this;

auto substOptions =
(shouldSubstituteOpaqueArchetypes
? SubstOptions(SubstFlags::SubstituteOpaqueArchetypes)
: SubstOptions(None));
InFlightSubstitution IFS(subs, conformances, substOptions);

InFlightSubstitution IFS(subs, conformances, options);
SILTypeSubstituter STST(tc, TypeExpansionContext::minimal(), IFS,
genericSig);
return STST.subst(*this);
}

SILType SILType::subst(TypeConverter &tc, InFlightSubstitution &IFS,
CanGenericSignature genericSig) const {
if (isSubstitutionInvariant(*this, IFS.shouldSubstituteOpaqueArchetypes()))
if (isSubstitutionInvariant(*this, IFS.getOptions()))
return *this;

SILTypeSubstituter STST(tc, TypeExpansionContext::minimal(), IFS,
Expand All @@ -504,9 +498,8 @@ SILType SILType::subst(TypeConverter &tc, InFlightSubstitution &IFS,
SILType SILType::subst(SILModule &M, TypeSubstitutionFn subs,
LookupConformanceFn conformances,
CanGenericSignature genericSig,
bool shouldSubstituteOpaqueArchetypes) const {
return subst(M.Types, subs, conformances, genericSig,
shouldSubstituteOpaqueArchetypes);
SubstOptions options) const {
return subst(M.Types, subs, conformances, genericSig, options);
}

SILType SILType::subst(TypeConverter &tc, SubstitutionMap subs) const {
Expand All @@ -521,7 +514,7 @@ SILType SILType::subst(SILModule &M, SubstitutionMap subs) const{

SILType SILType::subst(SILModule &M, SubstitutionMap subs,
TypeExpansionContext context) const {
if (isSubstitutionInvariant(*this, false))
if (isSubstitutionInvariant(*this, None))
return *this;

InFlightSubstitutionViaSubMap IFS(subs, None);
Expand Down
12 changes: 1 addition & 11 deletions lib/SILGen/SILGenConstructor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,17 +284,7 @@ static SubstitutionMap getSubstitutionsForPropertyInitializer(
// replacement types are the archetypes of the initializer itself.
return SubstitutionMap::get(
nominal->getGenericSignatureOfContext(),
[&](SubstitutableType *type) -> Type {
if (auto gp = type->getAs<GenericTypeParamType>()) {
auto archetype = genericEnv->mapTypeIntoContext(gp);
if (!gp->isParameterPack())
return archetype;

return PackType::getSingletonPackExpansion(archetype);
}

return Type(type);
},
QuerySubstitutionMap{genericEnv->getForwardingSubstitutionMap()},
LookUpConformanceInModule(dc->getParentModule()));
}

Expand Down
26 changes: 16 additions & 10 deletions lib/SILGen/SILGenProlog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -910,19 +910,25 @@ static void makeArgument(Type ty, ParamDecl *decl,
SmallVectorImpl<SILValue> &args, SILGenFunction &SGF) {
assert(ty && "no type?!");

if (ty->is<PackExpansionType>()) {
ty = PackType::get(SGF.getASTContext(), {ty});
}

// Destructure tuple value arguments.
if (TupleType *tupleTy = decl->isInOut() ? nullptr : ty->getAs<TupleType>()) {
for (auto fieldType : tupleTy->getElementTypes())
makeArgument(fieldType, decl, args, SGF);
} else {
auto loweredTy = SGF.getLoweredTypeForFunctionArgument(ty);
if (decl->isInOut())
loweredTy = SILType::getPrimitiveAddressType(loweredTy.getASTType());
auto arg = SGF.F.begin()->createFunctionArgument(loweredTy, decl);
args.push_back(arg);
if (!decl->isInOut()) {
if (TupleType *tupleTy = ty->getAs<TupleType>()) {
for (auto fieldType : tupleTy->getElementTypes())
makeArgument(fieldType, decl, args, SGF);
return;
}
}
}

auto loweredTy = SGF.getLoweredTypeForFunctionArgument(ty);
if (decl->isInOut())
loweredTy = SILType::getPrimitiveAddressType(loweredTy.getASTType());
auto arg = SGF.F.begin()->createFunctionArgument(loweredTy, decl);
args.push_back(arg);
}

void SILGenFunction::bindParameterForForwarding(ParamDecl *param,
SmallVectorImpl<SILValue> &parameters) {
Expand Down
29 changes: 29 additions & 0 deletions lib/Sema/TypeCheckGeneric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1062,6 +1062,35 @@ CheckGenericArgumentsResult::Kind TypeChecker::checkGenericArguments(
return CheckGenericArgumentsResult::Success;
}

CheckGenericArgumentsResult::Kind TypeChecker::checkGenericArguments(
ArrayRef<Requirement> requirements) {
SmallVector<Requirement, 4> worklist(requirements.begin(), requirements.end());

bool hadSubstFailure = false;

while (!worklist.empty()) {
auto req = worklist.pop_back_val();
switch (req.checkRequirement(worklist, /*allowMissing=*/true)) {
case CheckRequirementResult::Success:
case CheckRequirementResult::ConditionalConformance:
case CheckRequirementResult::PackRequirement:
break;

case CheckRequirementResult::RequirementFailure:
return CheckGenericArgumentsResult::RequirementFailure;

case CheckRequirementResult::SubstitutionFailure:
hadSubstFailure = true;
break;
}
}

if (hadSubstFailure)
return CheckGenericArgumentsResult::SubstitutionFailure;

return CheckGenericArgumentsResult::Success;
}

Requirement
RequirementRequest::evaluate(Evaluator &evaluator,
WhereClauseOwner owner,
Expand Down
4 changes: 1 addition & 3 deletions lib/Sema/TypeCheckProtocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5733,9 +5733,7 @@ TypeChecker::conformsToProtocol(Type T, ProtocolDecl *Proto, ModuleDecl *M,

// If we have a conditional requirements that we need to check, do so now.
if (!condReqs->empty()) {
auto conditionalCheckResult = checkGenericArguments(
M, *condReqs,
[](SubstitutableType *dependentType) { return Type(dependentType); });
auto conditionalCheckResult = checkGenericArguments(*condReqs);
switch (conditionalCheckResult) {
case CheckGenericArgumentsResult::Success:
break;
Expand Down
4 changes: 4 additions & 0 deletions lib/Sema/TypeChecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,10 @@ checkGenericArguments(ModuleDecl *module, ArrayRef<Requirement> requirements,
TypeSubstitutionFn substitutions,
SubstOptions options = None);

/// Check the given requirements without applying substitutions.
CheckGenericArgumentsResult::Kind
checkGenericArguments(ArrayRef<Requirement> requirements);

/// Checks whether the generic requirements imposed on the nested type
/// declaration \p decl (if present) are in agreement with the substitutions
/// that are needed to spell it as a member of the given parent type
Expand Down
1 change: 1 addition & 0 deletions lib/Serialization/Serialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5652,6 +5652,7 @@ void Serializer::writeAllDeclsAndTypes() {
registerDeclTypeAbbr<OptionalTypeLayout>();
registerDeclTypeAbbr<DynamicSelfTypeLayout>();
registerDeclTypeAbbr<PackExpansionTypeLayout>();
registerDeclTypeAbbr<PackElementTypeLayout>();
registerDeclTypeAbbr<PackTypeLayout>();
registerDeclTypeAbbr<SILPackTypeLayout>();

Expand Down
17 changes: 17 additions & 0 deletions test/SILGen/variadic_generic_allocating_init.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// RUN: %target-swift-emit-silgen %s -disable-availability-checking | %FileCheck %s

class C<each T> {
var values: (repeat each T)

// CHECK-LABEL: sil hidden [exact_self_class] [ossa] @$s32variadic_generic_allocating_init1CC9fromTupleACyxxQp_QPGxxQp_t_tcfC : $@convention(method) <each T> (@pack_owned Pack{repeat each T}, @thick C<repeat each T>.Type) -> @owned C<repeat each T> {
// CHECK: bb0(%0 : $*Pack{repeat each T}, %1 : $@thick C<repeat each T>.Type):
init(fromTuple: (repeat each T)) {
self.values = fromTuple
}

// CHECK-LABEL: sil hidden [exact_self_class] [ossa] @$s32variadic_generic_allocating_init1CC8fromPackACyxxQp_QPGxxQp_tcfC : $@convention(method) <each T> (@pack_owned Pack{repeat each T}, @thick C<repeat each T>.Type) -> @owned C<repeat each T> {
// CHECK: bb0(%0 : $*Pack{repeat each T}, %1 : $@thick C<repeat each T>.Type):
init(fromPack: repeat each T) {
self.values = (repeat each fromPack)
}
}