Skip to content

Allow forming PackExpansionTypes in expression context #62414

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 5 commits into from
Dec 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions include/swift/SIL/AbstractionPattern.h
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,20 @@ class AbstractionPattern {
return false;
}
}

bool isTypeParameterPack() const {
switch (getKind()) {
case Kind::Opaque:
return false;
case Kind::Type:
case Kind::ClangType:
case Kind::Discard: {
return getType()->isParameterPack();
}
default:
return false;
}
}

/// Is this an interface type that is subject to a concrete
/// same-type constraint?
Expand Down
36 changes: 4 additions & 32 deletions lib/IRGen/GenProto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2920,14 +2920,6 @@ void NecessaryBindings::save(IRGenFunction &IGF, Address buffer) const {
void NecessaryBindings::addTypeMetadata(CanType type) {
assert(!isa<InOutType>(type));

// If the bindings are for an async function, we will always need the type
// metadata. The opportunities to reconstruct it available in the context of
// partial apply forwarders are not available here.
if (forAsyncFunction()) {
addRequirement({type, nullptr});
return;
}

// Bindings are only necessary at all if the type is dependent.
if (!type->hasArchetype())
return;
Expand Down Expand Up @@ -2995,21 +2987,12 @@ void NecessaryBindings::addProtocolConformance(CanType type,
dyn_cast<SpecializedProtocolConformance>(concreteConformance);
// The partial apply forwarder does not have the context to reconstruct
// abstract conditional conformance requirements.
if (forPartialApply() && specializedConf) {
if (specializedConf) {
addAbstractConditionalRequirements(specializedConf);
} else if (forAsyncFunction()) {
ProtocolDecl *protocol = conf.getRequirement();
GenericRequirement requirement;
requirement.TypeParameter = type;
requirement.Protocol = protocol;
std::pair<GenericRequirement, ProtocolConformanceRef> pair{requirement,
conf};
Conformances.insert(pair);
addRequirement({type, concreteConformance->getProtocol()});
}
return;
}
assert(isa<ArchetypeType>(type) || forAsyncFunction());
assert(isa<ArchetypeType>(type));

// TODO: pass something about the root conformance necessary to
// reconstruct this.
Expand Down Expand Up @@ -3204,29 +3187,20 @@ void EmitPolymorphicArguments::emit(SubstitutionMap subs,
}
}

NecessaryBindings NecessaryBindings::forAsyncFunctionInvocation(
IRGenModule &IGM, CanSILFunctionType origType, SubstitutionMap subs) {
return computeBindings(IGM, origType, subs,
false /*forPartialApplyForwarder*/);
}

NecessaryBindings
NecessaryBindings::forPartialApplyForwarder(IRGenModule &IGM,
CanSILFunctionType origType,
SubstitutionMap subs,
bool considerParameterSources) {
return computeBindings(IGM, origType, subs,
true /*forPartialApplyForwarder*/,
considerParameterSources);
}

NecessaryBindings NecessaryBindings::computeBindings(
IRGenModule &IGM, CanSILFunctionType origType, SubstitutionMap subs,
bool forPartialApplyForwarder, bool considerParameterSources) {
bool considerParameterSources) {

NecessaryBindings bindings;
bindings.kind =
forPartialApplyForwarder ? Kind::PartialApply : Kind::AsyncFunction;

// Bail out early if we don't have polymorphic parameters.
if (!hasPolymorphicParameters(origType))
Expand All @@ -3249,9 +3223,7 @@ NecessaryBindings NecessaryBindings::computeBindings(
case MetadataSource::Kind::SelfMetadata:
// Async functions pass the SelfMetadata and SelfWitnessTable parameters
// along explicitly.
if (forPartialApplyForwarder) {
bindings.addTypeMetadata(getSubstSelfType(IGM, origType, subs));
}
bindings.addTypeMetadata(getSubstSelfType(IGM, origType, subs));
continue;

case MetadataSource::Kind::SelfWitnessTable:
Expand Down
42 changes: 3 additions & 39 deletions lib/IRGen/NecessaryBindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,28 +42,11 @@ namespace swift {
/// NecessaryBindings - The set of metadata that must be saved in
/// order to perform some set of operations on a type.
class NecessaryBindings {
enum class Kind {
/// Are the bindings to be computed for a partial apply forwarder.
/// In the case this is true we need to store/restore the conformance of a
/// specialized type with conditional conformance because the conditional
/// requirements are not available in the partial apply forwarder.
PartialApply,
AsyncFunction,
};
Kind kind;
llvm::SetVector<GenericRequirement> RequirementsSet;
llvm::SmallVector<GenericRequirement, 2> RequirementsVector;
llvm::DenseMap<GenericRequirement, ProtocolConformanceRef> Conformances;

void addRequirement(GenericRequirement requirement) {
switch (kind) {
case Kind::PartialApply:
RequirementsSet.insert(requirement);
break;
case Kind::AsyncFunction:
RequirementsVector.push_back(requirement);
break;
}
RequirementsSet.insert(requirement);
}

void addAbstractConditionalRequirements(
Expand All @@ -74,9 +57,6 @@ class NecessaryBindings {

/// Collect the necessary bindings to invoke a function with the given
/// signature.
static NecessaryBindings
forAsyncFunctionInvocation(IRGenModule &IGM, CanSILFunctionType origType,
SubstitutionMap subs);
static NecessaryBindings forPartialApplyForwarder(IRGenModule &IGM,
CanSILFunctionType origType,
SubstitutionMap subs,
Expand All @@ -88,13 +68,7 @@ class NecessaryBindings {

/// Get the requirement from the bindings at index i.
const GenericRequirement &operator[](size_t i) const {
switch (kind) {
case Kind::PartialApply:
return RequirementsSet[i];
case Kind::AsyncFunction:
return RequirementsVector[i];
}
llvm_unreachable("covered switch");
return RequirementsSet[i];
}

ProtocolConformanceRef
Expand Down Expand Up @@ -124,23 +98,13 @@ class NecessaryBindings {
void restore(IRGenFunction &IGF, Address buffer, MetadataState state) const;

const llvm::ArrayRef<GenericRequirement> getRequirements() const {
switch (kind) {
case Kind::PartialApply:
return RequirementsSet.getArrayRef();
case Kind::AsyncFunction:
return RequirementsVector;
}
llvm_unreachable("unhandled case");
return RequirementsSet.getArrayRef();
}

bool forPartialApply() const { return kind == Kind::PartialApply; }
bool forAsyncFunction() const { return kind == Kind::AsyncFunction; }

private:
static NecessaryBindings computeBindings(IRGenModule &IGM,
CanSILFunctionType origType,
SubstitutionMap subs,
bool forPartialApplyForwarder,
bool considerParameterSources = true);
};

Expand Down
12 changes: 4 additions & 8 deletions lib/Parse/ParseExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1227,12 +1227,9 @@ Parser::parseExprPostfixSuffix(ParserResult<Expr> Result, bool isExprBasic,
if (argStat.isErrorOrHasCompletion())
diagnose(LAngleLoc, diag::while_parsing_as_left_angle_bracket);

// The result can be empty in error cases.
if (!args.empty()) {
Result = makeParserResult(
Result, UnresolvedSpecializeExpr::create(
Context, Result.get(), LAngleLoc, args, RAngleLoc));
}
Result = makeParserResult(
Result, UnresolvedSpecializeExpr::create(
Context, Result.get(), LAngleLoc, args, RAngleLoc));
}

continue;
Expand Down Expand Up @@ -2241,8 +2238,7 @@ ParserResult<Expr> Parser::parseExprIdentifier() {
if (argStatus.isErrorOrHasCompletion())
diagnose(LAngleLoc, diag::while_parsing_as_left_angle_bracket);

// The result can be empty in error cases.
hasGenericArgumentList = !args.empty();
hasGenericArgumentList = true;
}

if (name.getBaseName().isEditorPlaceholder()) {
Expand Down
34 changes: 20 additions & 14 deletions lib/Parse/ParseType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1365,13 +1365,18 @@ bool Parser::canParseGenericArguments() {
if (!startsWithLess(Tok))
return false;
consumeStartingLess();


if (startsWithGreater(Tok)) {
consumeStartingGreater();
return true;
}

do {
if (!canParseType())
return false;
// Parse the comma, if the list continues.
} while (consumeIf(tok::comma));

if (!startsWithGreater(Tok)) {
return false;
} else {
Expand Down Expand Up @@ -1454,19 +1459,20 @@ bool Parser::canParseType() {
break;
}

if (!isAtFunctionTypeArrow())
return true;

// Handle type-function if we have an '->' with optional
// 'async' and/or 'throws'.
while (isEffectsSpecifier(Tok))
consumeToken();
if (isAtFunctionTypeArrow()) {
// Handle type-function if we have an '->' with optional
// 'async' and/or 'throws'.
while (isEffectsSpecifier(Tok))
consumeToken();

if (!consumeIf(tok::arrow))
return false;

if (!canParseType())
return false;
if (!consumeIf(tok::arrow))
return false;

if (!canParseType())
return false;

return true;
}

// Parse pack expansion 'T...'.
if (Tok.isEllipsis()) {
Expand Down
35 changes: 31 additions & 4 deletions lib/SIL/IR/AbstractionPattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1584,7 +1584,15 @@ class SubstFunctionTypePatternVisitor
// If so, let's put a fresh generic parameter in the substituted signature
// here.
unsigned paramIndex = substGenericParams.size();
auto gp = GenericTypeParamType::get(false, 0, paramIndex, TC.Context);

bool isParameterPack = false;
if (substTy->isParameterPack() || substTy->is<PackArchetypeType>())
isParameterPack = true;
else if (pattern.isTypeParameterPack())
isParameterPack = true;

auto gp = GenericTypeParamType::get(isParameterPack, 0, paramIndex,
TC.Context);
substGenericParams.push_back(gp);
substReplacementTypes.push_back(substTy);

Expand Down Expand Up @@ -1881,11 +1889,30 @@ class SubstFunctionTypePatternVisitor
}

CanType visitPackType(PackType *pack, AbstractionPattern pattern) {
llvm_unreachable("Unimplemented!");
if (auto gp = handleTypeParameterInAbstractionPattern(pattern, pack))
return gp;

// Break down the pack.
SmallVector<Type, 4> packElts;
for (unsigned i = 0; i < pack->getNumElements(); ++i) {
packElts.push_back(visit(pack->getElementType(i),
pattern.getPackElementType(i)));
}

return CanType(PackType::get(TC.Context, packElts));
}

CanType visitPackExpansionType(PackExpansionType *pack, AbstractionPattern pattern) {
llvm_unreachable("Unimplemented!");
CanType visitPackExpansionType(PackExpansionType *pack,
AbstractionPattern pattern) {
// Avoid walking into the pattern and count type if we can help it.
if (!pack->hasTypeParameter() && !pack->hasArchetype() &&
!pack->hasOpaqueArchetype()) {
return CanType(pack);
}

return CanType(PackExpansionType::get(
visit(pack->getPatternType(), pattern.getPackExpansionPatternType()),
visit(pack->getCountType(), pattern.getPackExpansionCountType())));
}

CanType visitExistentialType(ExistentialType *exist,
Expand Down
Loading