Skip to content

Requestify Inferring Generic Requirements #26995

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 2 commits into from
Sep 5, 2019
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
1 change: 1 addition & 0 deletions include/swift/AST/ASTTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ SWIFT_TYPEID_NAMED(VarDecl *, VarDecl)
SWIFT_TYPEID_NAMED(ValueDecl *, ValueDecl)
SWIFT_TYPEID_NAMED(ProtocolDecl *, ProtocolDecl)
SWIFT_TYPEID_NAMED(Decl *, Decl)
SWIFT_TYPEID_NAMED(ModuleDecl *, ModuleDecl)
SWIFT_TYPEID(Type)
SWIFT_TYPEID(TypePair)
SWIFT_TYPEID(PropertyWrapperBackingPropertyInfo)
Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/ASTTypeIDs.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class Decl;
class GenericSignature;
class GenericTypeParamType;
class IterableDeclContext;
class ModuleDecl;
class NominalTypeDecl;
class OperatorDecl;
struct PropertyWrapperBackingPropertyInfo;
Expand Down
5 changes: 4 additions & 1 deletion include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1425,7 +1425,7 @@ class GenericParamList final :
/// to the given DeclContext.
GenericParamList *clone(DeclContext *dc) const;

void print(raw_ostream &OS);
void print(raw_ostream &OS) const;
void dump();
};

Expand Down Expand Up @@ -7261,6 +7261,9 @@ inline void simple_display(llvm::raw_ostream &out,
simple_display(out, static_cast<const Decl *>(decl));
}

/// Display GenericParamList.
void simple_display(llvm::raw_ostream &out, const GenericParamList *GPL);

/// Extract the source location from the given declaration.
SourceLoc extractNearestSourceLoc(const Decl *decl);

Expand Down
1 change: 0 additions & 1 deletion include/swift/AST/GenericSignatureBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,6 @@ class GenericSignatureBuilder {
/// because the type \c Dictionary<K,V> cannot be formed without it.
void inferRequirements(ModuleDecl &module,
Type type,
const TypeRepr *typeRepr,
FloatingRequirementSource source);

/// Infer requirements from the given pattern, recursively.
Expand Down
38 changes: 38 additions & 0 deletions include/swift/AST/TypeCheckRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -1103,6 +1103,43 @@ class AbstractGenericSignatureRequest :
}
};

class InferredGenericSignatureRequest :
public SimpleRequest<InferredGenericSignatureRequest,
GenericSignature *(ModuleDecl *,
GenericSignature *,
SmallVector<GenericParamList *, 2>,
SmallVector<Requirement, 2>,
SmallVector<TypeLoc, 2>,
bool),
CacheKind::Cached> {
public:
using SimpleRequest::SimpleRequest;

private:
friend SimpleRequest;

// Evaluation.
llvm::Expected<GenericSignature *>
evaluate(Evaluator &evaluator,
ModuleDecl *module,
GenericSignature *baseSignature,
SmallVector<GenericParamList *, 2> addedParameters,
SmallVector<Requirement, 2> addedRequirements,
SmallVector<TypeLoc, 2> inferenceSources,
bool allowConcreteGenericParams) const;

public:
// Separate caching.
bool isCached() const;

/// Inferred generic signature requests don't have source-location info.
SourceLoc getNearestLoc() const {
return SourceLoc();
}
};

void simple_display(llvm::raw_ostream &out, const TypeLoc source);

class ExtendedTypeRequest
: public SimpleRequest<ExtendedTypeRequest,
Type(ExtensionDecl *),
Expand Down Expand Up @@ -1149,6 +1186,7 @@ inline bool AnyValue::Holder<Type>::equals(const HolderBase &other) const {
}

void simple_display(llvm::raw_ostream &out, Type value);
void simple_display(llvm::raw_ostream &out, const TypeRepr *TyR);

#define SWIFT_TYPEID_ZONE TypeChecker
#define SWIFT_TYPEID_HEADER "swift/AST/TypeCheckerTypeIDZone.def"
Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/TypeCheckerTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ SWIFT_REQUEST(TypeChecker, ExistentialTypeSupportedRequest)
SWIFT_REQUEST(TypeChecker, ExtendedTypeRequest)
SWIFT_REQUEST(TypeChecker, FunctionBuilderTypeRequest)
SWIFT_REQUEST(TypeChecker, FunctionOperatorRequest)
SWIFT_REQUEST(TypeChecker, InferredGenericSignatureRequest)
SWIFT_REQUEST(TypeChecker, InheritedTypeRequest)
SWIFT_REQUEST(TypeChecker, InitKindRequest)
SWIFT_REQUEST(TypeChecker, IsAccessorTransparentRequest)
Expand Down
16 changes: 16 additions & 0 deletions include/swift/AST/TypeLoc.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,22 @@ struct TypeLoc {
void setType(Type Ty);

TypeLoc clone(ASTContext &ctx) const;

friend llvm::hash_code hash_value(const TypeLoc &owner) {
return hash_combine(llvm::hash_value(owner.Ty.getPointer()),
llvm::hash_value(owner.TyR));
}

friend bool operator==(const TypeLoc &lhs,
const TypeLoc &rhs) {
return lhs.Ty.getPointer() == rhs.Ty.getPointer()
&& lhs.TyR == rhs.TyR;
}

friend bool operator!=(const TypeLoc &lhs,
const TypeLoc &rhs) {
return !(lhs == rhs);
}
};

} // end namespace llvm
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ void RequirementRepr::print(ASTPrinter &out) const {
printImpl(out, /*AsWritten=*/true);
}

void GenericParamList::print(llvm::raw_ostream &OS) {
void GenericParamList::print(llvm::raw_ostream &OS) const {
OS << '<';
interleave(*this,
[&](const GenericTypeParamDecl *P) {
Expand Down
6 changes: 6 additions & 0 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7645,6 +7645,12 @@ void swift::simple_display(llvm::raw_ostream &out, const ValueDecl *decl) {
else out << "(null)";
}

void swift::simple_display(llvm::raw_ostream &out, const GenericParamList *GPL) {
if (GPL) GPL->print(out);
else out << "(null)";
}


StringRef swift::getAccessorLabel(AccessorKind kind) {
switch (kind) {
#define SINGLETON_ACCESSOR(ID, KEYWORD) \
Expand Down
110 changes: 102 additions & 8 deletions lib/AST/GenericSignatureBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5158,7 +5158,7 @@ ConstraintResult GenericSignatureBuilder::addInheritedRequirements(

auto visitType = [&](Type inheritedType, const TypeRepr *typeRepr) {
if (inferForModule) {
inferRequirements(*inferForModule, inheritedType, typeRepr,
inferRequirements(*inferForModule, inheritedType,
getFloatingSource(typeRepr, /*forInferred=*/true));
}

Expand Down Expand Up @@ -5200,11 +5200,9 @@ GenericSignatureBuilder::addRequirement(const Requirement &req,

if (inferForModule) {
inferRequirements(*inferForModule, firstType,
RequirementRepr::getFirstTypeRepr(reqRepr),
source.asInferred(
RequirementRepr::getFirstTypeRepr(reqRepr)));
inferRequirements(*inferForModule, secondType,
RequirementRepr::getSecondTypeRepr(reqRepr),
source.asInferred(
RequirementRepr::getSecondTypeRepr(reqRepr)));
}
Expand All @@ -5217,7 +5215,6 @@ GenericSignatureBuilder::addRequirement(const Requirement &req,
case RequirementKind::Layout: {
if (inferForModule) {
inferRequirements(*inferForModule, firstType,
RequirementRepr::getFirstTypeRepr(reqRepr),
source.asInferred(
RequirementRepr::getFirstTypeRepr(reqRepr)));
}
Expand All @@ -5231,11 +5228,9 @@ GenericSignatureBuilder::addRequirement(const Requirement &req,

if (inferForModule) {
inferRequirements(*inferForModule, firstType,
RequirementRepr::getFirstTypeRepr(reqRepr),
source.asInferred(
RequirementRepr::getFirstTypeRepr(reqRepr)));
inferRequirements(*inferForModule, secondType,
RequirementRepr::getSecondTypeRepr(reqRepr),
source.asInferred(
RequirementRepr::getSecondTypeRepr(reqRepr)));
}
Expand Down Expand Up @@ -5322,7 +5317,6 @@ class GenericSignatureBuilder::InferRequirementsWalker : public TypeWalker {
void GenericSignatureBuilder::inferRequirements(
ModuleDecl &module,
Type type,
const TypeRepr *typeRepr,
FloatingRequirementSource source) {
if (!type)
return;
Expand All @@ -5337,7 +5331,6 @@ void GenericSignatureBuilder::inferRequirements(
ParameterList *params) {
for (auto P : *params) {
inferRequirements(module, P->getTypeLoc().getType(),
P->getTypeLoc().getTypeRepr(),
FloatingRequirementSource::forInferred(
P->getTypeLoc().getTypeRepr()));
}
Expand Down Expand Up @@ -7545,6 +7538,10 @@ bool AbstractGenericSignatureRequest::isCached() const {
return true;
}

bool InferredGenericSignatureRequest::isCached() const {
return true;
}

/// Check whether the inputs to the \c AbstractGenericSignatureRequest are
/// all canonical.
static bool isCanonicalRequest(GenericSignature *baseSignature,
Expand Down Expand Up @@ -7678,3 +7675,100 @@ AbstractGenericSignatureRequest::evaluate(
return std::move(builder).computeGenericSignature(
SourceLoc(), /*allowConcreteGenericParams=*/true);
}

llvm::Expected<GenericSignature *>
InferredGenericSignatureRequest::evaluate(
Evaluator &evaluator, ModuleDecl *parentModule,
GenericSignature *parentSig,
SmallVector<GenericParamList *, 2> gpLists,
SmallVector<Requirement, 2> addedRequirements,
SmallVector<TypeLoc, 2> inferenceSources,
bool allowConcreteGenericParams) const {

GenericSignatureBuilder builder(parentModule->getASTContext());

// If there is a parent context, add the generic parameters and requirements
// from that context.
builder.addGenericSignature(parentSig);

// The generic parameter lists MUST appear from innermost to outermost.
// We walk them backwards to order outer requirements before
// inner requirements.
for (auto &genericParams : llvm::reverse(gpLists)) {
assert(genericParams->size() > 0 &&
"Parsed an empty generic parameter list?");

// Determine where and how to perform name lookup.
DeclContext *lookupDC = genericParams->begin()[0]->getDeclContext();

// First, add the generic parameters to the generic signature builder.
// Do this before checking the inheritance clause, since it may
// itself be dependent on one of these parameters.
for (auto param : *genericParams)
builder.addGenericParameter(param);

// Add the requirements for each of the generic parameters to the builder.
// Now, check the inheritance clauses of each parameter.
for (auto param : *genericParams)
builder.addGenericParameterRequirements(param);

// Add the requirements clause to the builder.

WhereClauseOwner owner(lookupDC, genericParams);
using FloatingRequirementSource =
GenericSignatureBuilder::FloatingRequirementSource;
RequirementRequest::visitRequirements(owner, TypeResolutionStage::Structural,
[&](const Requirement &req, RequirementRepr *reqRepr) {
auto source = FloatingRequirementSource::forExplicit(reqRepr);

// If we're extending a protocol and adding a redundant requirement,
// for example, `extension Foo where Self: Foo`, then emit a
// diagnostic.

if (auto decl = owner.dc->getAsDecl()) {
if (auto extDecl = dyn_cast<ExtensionDecl>(decl)) {
auto extType = extDecl->getDeclaredInterfaceType();
auto extSelfType = extDecl->getSelfInterfaceType();
auto reqLHSType = req.getFirstType();
auto reqRHSType = req.getSecondType();

if (extType->isExistentialType() &&
reqLHSType->isEqual(extSelfType) &&
reqRHSType->isEqual(extType)) {

auto &ctx = extDecl->getASTContext();
ctx.Diags.diagnose(extDecl->getLoc(),
diag::protocol_extension_redundant_requirement,
extType->getString(),
extSelfType->getString(),
reqRHSType->getString());
}
}
}

builder.addRequirement(req, reqRepr, source, nullptr,
lookupDC->getParentModule());
return false;
});
}

/// Perform any remaining requirement inference.
for (auto sourcePair : inferenceSources) {
auto source =
FloatingRequirementSource::forInferred(sourcePair.getTypeRepr());

builder.inferRequirements(*parentModule,
sourcePair.getType(),
source);
}

// Finish by adding any remaining requirements.
auto source =
FloatingRequirementSource::forInferred(nullptr);

for (const auto &req : addedRequirements)
builder.addRequirement(req, source, parentModule);

return std::move(builder).computeGenericSignature(
SourceLoc(), allowConcreteGenericParams);
}
15 changes: 15 additions & 0 deletions lib/AST/TypeCheckRequests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,21 @@ void swift::simple_display(llvm::raw_ostream &out, Type type) {
out << "null";
}

void swift::simple_display(llvm::raw_ostream &out, const TypeRepr *TyR) {
if (TyR)
TyR->print(out);
else
out << "null";
}

void swift::simple_display(llvm::raw_ostream &out, const TypeLoc source) {
out << "(";
simple_display(out, source.getType());
out << ", ";
simple_display(out, source.getTypeRepr());
out << ")";
}

//----------------------------------------------------------------------------//
// Inherited type computation.
//----------------------------------------------------------------------------//
Expand Down
Loading