Skip to content

Commit

Permalink
AST: Store the GenericSignature in the AbstractFunctionDecl, NFC
Browse files Browse the repository at this point in the history
For better or worse, the type of a function can end up as ErrorType,
and the generic signature was not stored anywhere else, causing
crashes from orphaned generic type parameters.

This patch is the first in a series to make this more robust by
storing the generic signature before the interface type is computed.
  • Loading branch information
slavapestov committed Dec 14, 2015
1 parent d56cbfa commit dfbb580
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 32 deletions.
14 changes: 13 additions & 1 deletion include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -4371,6 +4371,7 @@ class AbstractFunctionDecl : public ValueDecl, public DeclContext {
};

GenericParamList *GenericParams;
GenericSignature *GenericSig;

CaptureInfo Captures;

Expand All @@ -4379,7 +4380,7 @@ class AbstractFunctionDecl : public ValueDecl, public DeclContext {
GenericParamList *GenericParams)
: ValueDecl(Kind, Parent, Name, NameLoc),
DeclContext(DeclContextKind::AbstractFunctionDecl, Parent),
Body(nullptr), GenericParams(nullptr) {
Body(nullptr), GenericParams(nullptr), GenericSig(nullptr) {
setBodyKind(BodyKind::None);
setGenericParams(GenericParams);
AbstractFunctionDeclBits.NumParamPatterns = NumParamPatterns;
Expand All @@ -4396,6 +4397,17 @@ class AbstractFunctionDecl : public ValueDecl, public DeclContext {
}

void setGenericParams(GenericParamList *GenericParams);

public:
void setGenericSignature(GenericSignature *GenericSig) {
assert(!this->GenericSig && "already have signature?");
this->GenericSig = GenericSig;
}

GenericSignature *getGenericSignature() const {
return GenericSig;
}

public:
// FIXME: Hack that provides names with keyword arguments for accessors.
DeclName getEffectiveFullName() const;
Expand Down
4 changes: 2 additions & 2 deletions lib/AST/DeclContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,8 @@ GenericSignature *DeclContext::getGenericSignatureOfContext() const {

case DeclContextKind::AbstractFunctionDecl: {
auto *AFD = cast<AbstractFunctionDecl>(this);
if (auto GFT = AFD->getInterfaceType()->getAs<GenericFunctionType>())
return GFT->getGenericSignature();
if (auto genericSig = AFD->getGenericSignature())
return genericSig;

// If we're within a type context, pick up the generic signature
// of that context.
Expand Down
59 changes: 32 additions & 27 deletions lib/Sema/TypeCheckGeneric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -653,16 +653,16 @@ static Type getResultType(TypeChecker &TC, FuncDecl *fn, Type resultType) {
}

bool TypeChecker::validateGenericFuncSignature(AbstractFunctionDecl *func) {
bool invalid = false;

// Create the archetype builder.
ArchetypeBuilder builder = createArchetypeBuilder(func->getParentModule());

// Type check the function declaration, treating all generic type
// parameters as dependent, unresolved.
DependentGenericTypeResolver dependentResolver(builder);
if (checkGenericFuncSignature(*this, &builder, func, dependentResolver)) {
func->overwriteType(ErrorType::get(Context));
return true;
}
if (checkGenericFuncSignature(*this, &builder, func, dependentResolver))
invalid = true;

// If this triggered a recursive validation, back out: we're done.
// FIXME: This is an awful hack.
Expand All @@ -677,10 +677,8 @@ bool TypeChecker::validateGenericFuncSignature(AbstractFunctionDecl *func) {
// function signature and type-check it again, completely.
revertGenericFuncSignature(func);
CompleteGenericTypeResolver completeResolver(*this, builder);
if (checkGenericFuncSignature(*this, nullptr, func, completeResolver)) {
func->overwriteType(ErrorType::get(Context));
return true;
}
if (checkGenericFuncSignature(*this, nullptr, func, completeResolver))
invalid = true;

// The generic function signature is complete and well-formed. Determine
// the type of the generic function.
Expand All @@ -694,6 +692,32 @@ bool TypeChecker::validateGenericFuncSignature(AbstractFunctionDecl *func) {
// Collect the requirements placed on the generic parameter types.
SmallVector<Requirement, 4> requirements;
collectRequirements(builder, allGenericParams, requirements);

auto sig = GenericSignature::get(allGenericParams, requirements);

// Debugging of the archetype builder and generic signature generation.
if (sig && Context.LangOpts.DebugGenericSignatures) {
func->dumpRef(llvm::errs());
llvm::errs() << "\n";
builder.dump(llvm::errs());
llvm::errs() << "Generic signature: ";
sig->print(llvm::errs());
llvm::errs() << "\n";
llvm::errs() << "Canonical generic signature: ";
sig->getCanonicalSignature()->print(llvm::errs());
llvm::errs() << "\n";
llvm::errs() << "Canonical generic signature for mangling: ";
sig->getCanonicalManglingSignature(*func->getParentModule())
->print(llvm::errs());
llvm::errs() << "\n";
}

func->setGenericSignature(sig);

if (invalid) {
func->overwriteType(ErrorType::get(Context));
return true;
}

// Compute the function type.
Type funcTy;
Expand Down Expand Up @@ -742,25 +766,6 @@ bool TypeChecker::validateGenericFuncSignature(AbstractFunctionDecl *func) {
patterns = storedPatterns;
}

auto sig = GenericSignature::get(allGenericParams, requirements);

// Debugging of the archetype builder and generic signature generation.
if (Context.LangOpts.DebugGenericSignatures) {
func->dumpRef(llvm::errs());
llvm::errs() << "\n";
builder.dump(llvm::errs());
llvm::errs() << "Generic signature: ";
sig->print(llvm::errs());
llvm::errs() << "\n";
llvm::errs() << "Canonical generic signature: ";
sig->getCanonicalSignature()->print(llvm::errs());
llvm::errs() << "\n";
llvm::errs() << "Canonical generic signature for mangling: ";
sig->getCanonicalManglingSignature(*func->getParentModule())
->print(llvm::errs());
llvm::errs() << "\n";
}

bool hasSelf = func->getDeclContext()->isTypeContext();
for (unsigned i = 0, e = patterns.size(); i != e; ++i) {
Type argTy;
Expand Down
10 changes: 8 additions & 2 deletions lib/Serialization/Deserialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2238,8 +2238,11 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional<DeclContext *> ForcedContext) {
// A polymorphic constructor type needs to refer to the constructor to get
// its generic parameters.
ctor->setType(getType(signatureID));
if (auto interfaceType = getType(interfaceID))
if (auto interfaceType = getType(interfaceID)) {
if (auto genericFnType = interfaceType->getAs<GenericFunctionType>())
ctor->setGenericSignature(genericFnType->getGenericSignature());
ctor->setInterfaceType(interfaceType);
}

// Set the initializer type of the constructor.
auto allocType = ctor->getType();
Expand Down Expand Up @@ -2480,8 +2483,11 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional<DeclContext *> ForcedContext) {
fn->setType(signature);

// Set the interface type.
if (auto interfaceType = getType(interfaceTypeID))
if (auto interfaceType = getType(interfaceTypeID)) {
if (auto genericFnType = interfaceType->getAs<GenericFunctionType>())
fn->setGenericSignature(genericFnType->getGenericSignature());
fn->setInterfaceType(interfaceType);
}

SmallVector<Pattern *, 16> patternBuf;
while (Pattern *pattern = maybeReadPattern())
Expand Down

0 comments on commit dfbb580

Please sign in to comment.