Introduce a new representation of polymorphic function types.

Introduces a new kind of function type, GenericFunctionType, that
represents a polymorphic function type with all of its generic
parameters and requirements stored in a more readily canonicalizable
form. It is meant to eventually replace PolymorphicFunctionType, but
for now we build it up in parallel so we can switch over to it
pieacemeal.

Note: this representation is built and then thrown away. We'll start
recording it soon.


Swift SVN r8881
This commit is contained in:
Doug Gregor
2013-10-03 17:59:35 +00:00
parent 781dcf7b11
commit 12e228c0f1
23 changed files with 999 additions and 165 deletions

View File

@@ -32,7 +32,7 @@ class ArchetypeType;
class AssociatedTypeDecl; class AssociatedTypeDecl;
class Pattern; class Pattern;
class ProtocolDecl; class ProtocolDecl;
class Requirement; class RequirementRepr;
class SourceLoc; class SourceLoc;
class TranslationUnit; class TranslationUnit;
class Type; class Type;
@@ -104,6 +104,9 @@ public:
ArchetypeBuilder(ArchetypeBuilder &&); ArchetypeBuilder(ArchetypeBuilder &&);
~ArchetypeBuilder(); ~ArchetypeBuilder();
/// Retrieve the translation unit.
TranslationUnit &getTranslationUnit() const { return TU; }
/// \brief Add a new generic parameter for which there may be requirements. /// \brief Add a new generic parameter for which there may be requirements.
/// ///
/// \returns true if an error occurred, false otherwise. /// \returns true if an error occurred, false otherwise.
@@ -114,7 +117,7 @@ public:
/// ///
/// \returns true if this requirement makes the set of requirements /// \returns true if this requirement makes the set of requirements
/// inconsistent, in which case a diagnostic will have been issued. /// inconsistent, in which case a diagnostic will have been issued.
bool addRequirement(const Requirement &Req); bool addRequirement(const RequirementRepr &Req);
/// \brief Add a new, implicit conformance requirement for one of the /// \brief Add a new, implicit conformance requirement for one of the
/// parameters. /// parameters.
@@ -180,7 +183,6 @@ public:
/// list. /// list.
ArrayRef<ArchetypeType *> getAllArchetypes(); ArrayRef<ArchetypeType *> getAllArchetypes();
// FIXME: Infer requirements from signatures
// FIXME: Compute the set of 'extra' witness tables needed to express this // FIXME: Compute the set of 'extra' witness tables needed to express this
// requirement set. // requirement set.
@@ -233,6 +235,10 @@ public:
/// \brief Retrieve the full display name of this potential archetype. /// \brief Retrieve the full display name of this potential archetype.
std::string getFullName() const; std::string getFullName() const;
/// Retrieve the parent of this potential archetype, which will be non-null
/// when this potential archetype is an associated type.
PotentialArchetype *getParent() const { return Parent; }
/// Retrieve the set of protocols to which this type conforms. /// Retrieve the set of protocols to which this type conforms.
ArrayRef<ProtocolDecl *> getConformsTo() const { ArrayRef<ProtocolDecl *> getConformsTo() const {
return llvm::makeArrayRef(ConformsTo.begin(), ConformsTo.end()); return llvm::makeArrayRef(ConformsTo.begin(), ConformsTo.end());
@@ -241,6 +247,11 @@ public:
/// Retrieve the superclass of this archetype. /// Retrieve the superclass of this archetype.
Type getSuperclass() const { return Superclass; } Type getSuperclass() const { return Superclass; }
/// Retrieve the set of nested types.
const llvm::DenseMap<Identifier, PotentialArchetype*> &getNestedTypes() const{
return NestedTypes;
}
/// \brief Determine the nesting depth of this potential archetype, e.g., /// \brief Determine the nesting depth of this potential archetype, e.g.,
/// the number of associated type references. /// the number of associated type references.
unsigned getNestingDepth() const; unsigned getNestingDepth() const;
@@ -257,6 +268,9 @@ public:
ArchetypeType *getArchetype(AssociatedTypeDecl * /*nullable*/ rootAssocTy, ArchetypeType *getArchetype(AssociatedTypeDecl * /*nullable*/ rootAssocTy,
TranslationUnit &tu); TranslationUnit &tu);
/// Retrieve the associated type declaration for a given nested type.
AssociatedTypeDecl *getAssociatedType(TranslationUnit &tu, Identifier name);
void dump(llvm::raw_ostream &Out, unsigned Indent); void dump(llvm::raw_ostream &Out, unsigned Indent);
friend class ArchetypeBuilder; friend class ArchetypeBuilder;

View File

@@ -23,6 +23,7 @@
#include "swift/AST/DefaultArgumentKind.h" #include "swift/AST/DefaultArgumentKind.h"
#include "swift/AST/KnownProtocols.h" #include "swift/AST/KnownProtocols.h"
#include "swift/AST/Identifier.h" #include "swift/AST/Identifier.h"
#include "swift/AST/Requirement.h"
#include "swift/AST/Substitution.h" #include "swift/AST/Substitution.h"
#include "swift/AST/Type.h" #include "swift/AST/Type.h"
#include "swift/AST/TypeLoc.h" #include "swift/AST/TypeLoc.h"
@@ -427,30 +428,19 @@ public:
void setDeclContext(DeclContext *DC); void setDeclContext(DeclContext *DC);
}; };
/// \brief Describes the kind of a requirement that occurs within a requirements
/// clause.
enum class RequirementKind : unsigned int {
/// \brief A conformance requirement T : P, where T is a type that depends
/// on a generic parameter and P is a protocol to which T must conform.
Conformance,
/// \brief A same-type requirement T == U, where T and U are types that
/// shall be equivalent.
SameType
};
/// \brief A single requirement in a 'where' clause, which places additional /// \brief A single requirement in a 'where' clause, which places additional
/// restrictions on the generic parameters or associated types of a generic /// restrictions on the generic parameters or associated types of a generic
/// function, type, or protocol. /// function, type, or protocol.
/// ///
/// This always represents a requirement spelled in the source code. It is /// This always represents a requirement spelled in the source code. It is
/// never generated implicitly. /// never generated implicitly.
class Requirement { class RequirementRepr {
SourceLoc SeparatorLoc; SourceLoc SeparatorLoc;
RequirementKind Kind : 1; RequirementKind Kind : 1;
bool Invalid : 1; bool Invalid : 1;
TypeLoc Types[2]; TypeLoc Types[2];
Requirement(SourceLoc SeparatorLoc, RequirementKind Kind, TypeLoc FirstType, RequirementRepr(SourceLoc SeparatorLoc, RequirementKind Kind, TypeLoc FirstType,
TypeLoc SecondType) TypeLoc SecondType)
: SeparatorLoc(SeparatorLoc), Kind(Kind), Invalid(false), : SeparatorLoc(SeparatorLoc), Kind(Kind), Invalid(false),
Types{FirstType, SecondType} { } Types{FirstType, SecondType} { }
@@ -464,7 +454,7 @@ public:
/// this requirement was implied. /// this requirement was implied.
/// \param Constraint The protocol or protocol composition to which the /// \param Constraint The protocol or protocol composition to which the
/// subject must conform, or superclass from which the subject must inherit. /// subject must conform, or superclass from which the subject must inherit.
static Requirement getConformance(TypeLoc Subject, static RequirementRepr getConformance(TypeLoc Subject,
SourceLoc ColonLoc, SourceLoc ColonLoc,
TypeLoc Constraint) { TypeLoc Constraint) {
return { ColonLoc, RequirementKind::Conformance, Subject, Constraint }; return { ColonLoc, RequirementKind::Conformance, Subject, Constraint };
@@ -476,7 +466,7 @@ public:
/// \param EqualLoc The location of the '==' in the same-type constraint, or /// \param EqualLoc The location of the '==' in the same-type constraint, or
/// an invalid location if this requirement was implied. /// an invalid location if this requirement was implied.
/// \param SecondType The second type. /// \param SecondType The second type.
static Requirement getSameType(TypeLoc FirstType, static RequirementRepr getSameType(TypeLoc FirstType,
SourceLoc EqualLoc, SourceLoc EqualLoc,
TypeLoc SecondType) { TypeLoc SecondType) {
return { EqualLoc, RequirementKind::SameType, FirstType, SecondType }; return { EqualLoc, RequirementKind::SameType, FirstType, SecondType };
@@ -589,7 +579,7 @@ class GenericParamList {
SourceRange Brackets; SourceRange Brackets;
unsigned NumParams; unsigned NumParams;
SourceLoc WhereLoc; SourceLoc WhereLoc;
MutableArrayRef<Requirement> Requirements; MutableArrayRef<RequirementRepr> Requirements;
ArrayRef<ArchetypeType *> AllArchetypes; ArrayRef<ArchetypeType *> AllArchetypes;
GenericParamList *OuterParameters; GenericParamList *OuterParameters;
@@ -597,7 +587,7 @@ class GenericParamList {
GenericParamList(SourceLoc LAngleLoc, GenericParamList(SourceLoc LAngleLoc,
ArrayRef<GenericParam> Params, ArrayRef<GenericParam> Params,
SourceLoc WhereLoc, SourceLoc WhereLoc,
MutableArrayRef<Requirement> Requirements, MutableArrayRef<RequirementRepr> Requirements,
SourceLoc RAngleLoc); SourceLoc RAngleLoc);
public: public:
@@ -630,7 +620,7 @@ public:
SourceLoc LAngleLoc, SourceLoc LAngleLoc,
ArrayRef<GenericParam> Params, ArrayRef<GenericParam> Params,
SourceLoc WhereLoc, SourceLoc WhereLoc,
MutableArrayRef<Requirement> Requirements, MutableArrayRef<RequirementRepr> Requirements,
SourceLoc RAngleLoc); SourceLoc RAngleLoc);
MutableArrayRef<GenericParam> getParams() { MutableArrayRef<GenericParam> getParams() {
@@ -659,7 +649,7 @@ public:
/// This list may contain both explicitly-written requirements as well as /// This list may contain both explicitly-written requirements as well as
/// implicitly-generated requirements, and may be non-empty even if no /// implicitly-generated requirements, and may be non-empty even if no
/// 'where' keyword is present. /// 'where' keyword is present.
MutableArrayRef<Requirement> getRequirements() { return Requirements; } MutableArrayRef<RequirementRepr> getRequirements() { return Requirements; }
/// \brief Retrieve the set of additional requirements placed on these /// \brief Retrieve the set of additional requirements placed on these
/// generic parameters and types derived from them. /// generic parameters and types derived from them.
@@ -667,7 +657,7 @@ public:
/// This list may contain both explicitly-written requirements as well as /// This list may contain both explicitly-written requirements as well as
/// implicitly-generated requirements, and may be non-empty even if no /// implicitly-generated requirements, and may be non-empty even if no
/// 'where' keyword is present. /// 'where' keyword is present.
ArrayRef<Requirement> getRequirements() const { return Requirements; } ArrayRef<RequirementRepr> getRequirements() const { return Requirements; }
/// \brief Override the set of requirements associated with this generic /// \brief Override the set of requirements associated with this generic
/// parameter list. /// parameter list.
@@ -676,7 +666,7 @@ public:
/// to be a superset of the existing set of requirements (although this /// to be a superset of the existing set of requirements (although this
/// property is not checked here). It is assumed that the array reference /// property is not checked here). It is assumed that the array reference
/// refers to ASTContext-allocated memory. /// refers to ASTContext-allocated memory.
void overrideRequirements(MutableArrayRef<Requirement> NewRequirements) { void overrideRequirements(MutableArrayRef<RequirementRepr> NewRequirements) {
Requirements = NewRequirements; Requirements = NewRequirements;
} }
@@ -887,8 +877,8 @@ public:
} }
/// Note that we have already type-checked the inheritance clause. /// Note that we have already type-checked the inheritance clause.
void setCheckedInheritanceClause() { void setCheckedInheritanceClause(bool checked = true) {
ExtensionDeclBits.CheckedInheritanceClause = true; ExtensionDeclBits.CheckedInheritanceClause = checked;
} }
/// \brief Retrieve the set of protocols to which this extension conforms. /// \brief Retrieve the set of protocols to which this extension conforms.
@@ -1158,8 +1148,8 @@ public:
} }
/// Note that we have already type-checked the inheritance clause. /// Note that we have already type-checked the inheritance clause.
void setCheckedInheritanceClause() { void setCheckedInheritanceClause(bool checked = true) {
TypeDeclBits.CheckedInheritanceClause = true; TypeDeclBits.CheckedInheritanceClause = checked;
} }
/// \brief Retrieve the set of protocols to which this type conforms. /// \brief Retrieve the set of protocols to which this type conforms.

View File

@@ -0,0 +1,63 @@
//===--- Requirement.h - Swift Requirement ASTs -----------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines the Requirement class and subclasses.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_AST_REQUIREMENT_H
#define SWIFT_AST_REQUIREMENT_H
#include "swift/AST/Type.h"
#include "llvm/ADT/PointerIntPair.h"
namespace swift {
/// \brief Describes the kind of a requirement that occurs within a requirements
/// clause.
enum class RequirementKind : unsigned int {
/// \brief A conformance requirement T : P, where T is a type that depends
/// on a generic parameter and P is a protocol to which T must conform.
Conformance,
/// \brief A same-type requirement T == U, where T and U are types that
/// shall be equivalent.
SameType
};
/// \brief A single requirement placed on the type parameters (or associated
/// types thereof) of a
class Requirement {
llvm::PointerIntPair<Type, 1, RequirementKind> FirstTypeAndKind;
Type SecondType;
public:
/// Create a conformance or same-type requirement.
Requirement(RequirementKind kind, Type first, Type second)
: FirstTypeAndKind(first, kind), SecondType(second) { }
/// \brief Determine the kind of requirement.
RequirementKind getKind() const { return FirstTypeAndKind.getInt(); }
/// \brief Retrieve the first type.
Type getFirstType() const {
return FirstTypeAndKind.getPointer();
}
/// \brief Retrieve the second type.
Type getSecondType() const {
return SecondType;
}
};
} // end namespace swift
#endif

View File

@@ -117,7 +117,8 @@ TYPE(DependentMember, Type)
ABSTRACT_TYPE(AnyFunction, Type) ABSTRACT_TYPE(AnyFunction, Type)
TYPE(Function, AnyFunctionType) TYPE(Function, AnyFunctionType)
TYPE(PolymorphicFunction, AnyFunctionType) TYPE(PolymorphicFunction, AnyFunctionType)
TYPE_RANGE(AnyFunction, Function, PolymorphicFunction) TYPE(GenericFunction, AnyFunctionType)
TYPE_RANGE(AnyFunction, Function, GenericFunction)
TYPE(Array, Type) TYPE(Array, Type)
ABSTRACT_SUGARED_TYPE(SyntaxSugar, Type) ABSTRACT_SUGARED_TYPE(SyntaxSugar, Type)
SUGARED_TYPE(ArraySlice, SyntaxSugarType) SUGARED_TYPE(ArraySlice, SyntaxSugarType)

View File

@@ -20,6 +20,7 @@
#include "swift/AST/DeclContext.h" #include "swift/AST/DeclContext.h"
#include "swift/AST/DefaultArgumentKind.h" #include "swift/AST/DefaultArgumentKind.h"
#include "swift/AST/Ownership.h" #include "swift/AST/Ownership.h"
#include "swift/AST/Requirement.h"
#include "swift/AST/Type.h" #include "swift/AST/Type.h"
#include "swift/AST/Identifier.h" #include "swift/AST/Identifier.h"
#include "swift/Basic/ArrayRefView.h" #include "swift/Basic/ArrayRefView.h"
@@ -40,6 +41,7 @@ namespace swift {
class ClassDecl; class ClassDecl;
class ExprHandle; class ExprHandle;
class GenericTypeParamDecl; class GenericTypeParamDecl;
class GenericTypeParamType;
class GenericParam; class GenericParam;
class GenericParamList; class GenericParamList;
class Identifier; class Identifier;
@@ -361,12 +363,12 @@ private:
// Make vanilla new/delete illegal for Types. // Make vanilla new/delete illegal for Types.
void *operator new(size_t Bytes) throw() = delete; void *operator new(size_t Bytes) throw() = delete;
void operator delete(void *Data) throw() = delete; void operator delete(void *Data) throw() = delete;
void *operator new(size_t Bytes, void *Mem) throw() = delete;
public: public:
// Only allow allocation of Types using the allocator in ASTContext // Only allow allocation of Types using the allocator in ASTContext
// or by doing a placement new. // or by doing a placement new.
void *operator new(size_t bytes, const ASTContext &ctx, void *operator new(size_t bytes, const ASTContext &ctx,
AllocationArena arena, unsigned alignment = 8); AllocationArena arena, unsigned alignment = 8);
void *operator new(size_t Bytes, void *Mem) throw() { return Mem; }
}; };
/// ErrorType - This represents a type that was erroneously constructed. This /// ErrorType - This represents a type that was erroneously constructed. This
@@ -1394,7 +1396,83 @@ private:
const ASTContext &C); const ASTContext &C);
}; };
DEFINE_EMPTY_CAN_TYPE_WRAPPER(PolymorphicFunctionType, AnyFunctionType) DEFINE_EMPTY_CAN_TYPE_WRAPPER(PolymorphicFunctionType, AnyFunctionType)
/// Describes a generic function type.
///
/// A generic function type describes a function that is polymorphic with
/// respect to some set of generic parameters and the requirements placed
/// on those parameters and dependent member types thereof. The input and
/// output types of the generic function can be expressed in terms of those
/// generic parameters.
///
/// FIXME: \c GenericFunctionType is meant as a replacement for
/// \c PolymorphicFunctionType.
class GenericFunctionType : public AnyFunctionType,
public llvm::FoldingSetNode {
unsigned NumGenericParams;
unsigned NumRequirements;
/// Retrieve a mutable version of the generic parameters.
MutableArrayRef<GenericTypeParamType *> getGenericParamsBuffer() {
return { reinterpret_cast<GenericTypeParamType **>(this + 1),
NumGenericParams };
}
/// Retrieve a mutable verison of the requirements.
MutableArrayRef<Requirement> getRequirementsBuffer() {
void *genericParams = getGenericParamsBuffer().end();
return { reinterpret_cast<Requirement *>(genericParams),
NumRequirements };
}
/// Construct a new generic function type.
GenericFunctionType(ArrayRef<GenericTypeParamType *> genericParams,
ArrayRef<Requirement> requirements,
Type input,
Type result,
const ExtInfo &info,
const ASTContext *ctx);
public:
/// Create a new generic function type.
static GenericFunctionType *get(ArrayRef<GenericTypeParamType *> params,
ArrayRef<Requirement> requirements,
Type input,
Type result,
const ExtInfo &info,
const ASTContext &ctx);
/// Retrieve the generic parameters of this polymorphic function type.
ArrayRef<GenericTypeParamType *> getGenericParams() const {
return { reinterpret_cast<GenericTypeParamType * const *>(this + 1),
NumGenericParams };
}
/// Retrieve the requirements of this polymorphic function type.
ArrayRef<Requirement> getRequirements() const {
const void *genericParams = getGenericParams().end();
return { reinterpret_cast<const Requirement *>(genericParams),
NumRequirements };
}
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getGenericParams(), getRequirements(), getInput(), getResult(),
getExtInfo());
}
static void Profile(llvm::FoldingSetNodeID &ID,
ArrayRef<GenericTypeParamType *> params,
ArrayRef<Requirement> requirements,
Type input,
Type result,
const ExtInfo &info);
// Implement isa/cast/dyncast/etc.
static bool classof(const TypeBase *T) {
return T->getKind() == TypeKind::GenericFunction;
}
};
DEFINE_EMPTY_CAN_TYPE_WRAPPER(GenericFunctionType, AnyFunctionType)
/// ArrayType - An array type has a base type and either an unspecified or a /// ArrayType - An array type has a base type and either an unspecified or a
/// constant size. For example "int[]" and "int[4]". Array types cannot have /// constant size. For example "int[]" and "int[4]". Array types cannot have
/// size = 0. /// size = 0.
@@ -2274,6 +2352,19 @@ case TypeKind::Id:
function->getResult().findIf(pred); function->getResult().findIf(pred);
} }
case TypeKind::GenericFunction: {
auto function = cast<GenericFunctionType>(base);
for (auto param : function->getGenericParams())
if (Type(param).findIf(pred))
return true;
for (const auto &req : function->getRequirements())
if (req.getFirstType().findIf(pred) ||
req.getSecondType().findIf(pred))
return true;
return function->getInput().findIf(pred) ||
function->getResult().findIf(pred);
}
case TypeKind::Array: case TypeKind::Array:
return cast<ArrayType>(base)->getBaseType().findIf(pred); return cast<ArrayType>(base)->getBaseType().findIf(pred);
@@ -2535,6 +2626,72 @@ case TypeKind::Id:
ctx); ctx);
} }
case TypeKind::GenericFunction: {
GenericFunctionType *function = cast<GenericFunctionType>(base);
bool anyChanges = false;
// Transform generic parameters.
SmallVector<GenericTypeParamType *, 4> genericParams;
for (auto param : function->getGenericParams()) {
Type paramTy = Type(param).transform(ctx, fn);
if (!paramTy)
return Type();
if (auto newParam = paramTy->getAs<GenericTypeParamType>()) {
if (newParam != param)
anyChanges = true;
genericParams.push_back(newParam);
}
}
// Transform requirements.
SmallVector<Requirement, 4> requirements;
for (const auto &req : function->getRequirements()) {
auto firstType = req.getFirstType().transform(ctx, fn);
if (!firstType)
return Type();
auto secondType = req.getSecondType().transform(ctx, fn);
if (!secondType)
return Type();
if (firstType->isDependentType() || secondType->isDependentType()) {
if (firstType.getPointer() != req.getFirstType().getPointer() ||
secondType.getPointer() != req.getSecondType().getPointer())
anyChanges = true;
requirements.push_back(Requirement(req.getKind(), firstType,
secondType));
} else
anyChanges = true;
}
// Transform input type.
auto inputTy = function->getInput().transform(ctx, fn);
if (!inputTy)
return Type();
// Transform result type.
auto resultTy = function->getResult().transform(ctx, fn);
if (!resultTy)
return Type();
// Check whether anything changed.
if (!anyChanges &&
inputTy.getPointer() == function->getInput().getPointer() &&
resultTy.getPointer() == function->getResult().getPointer())
return *this;
// If no generic parameters remain, this is a non-generic function type.
if (genericParams.empty())
return FunctionType::get(inputTy, resultTy, function->getExtInfo(), ctx);
// Produce the new generic function type.
return GenericFunctionType::get(genericParams, requirements, inputTy,
resultTy, function->getExtInfo(), ctx);
}
case TypeKind::Array: { case TypeKind::Array: {
auto array = cast<ArrayType>(base); auto array = cast<ArrayType>(base);
auto baseTy = array->getBaseType().transform(ctx, fn); auto baseTy = array->getBaseType().transform(ctx, fn);

View File

@@ -727,7 +727,7 @@ public:
GenericParamList *parseGenericParameters(SourceLoc LAngleLoc); GenericParamList *parseGenericParameters(SourceLoc LAngleLoc);
GenericParamList *maybeParseGenericParams(); GenericParamList *maybeParseGenericParams();
bool parseGenericWhereClause(SourceLoc &WhereLoc, bool parseGenericWhereClause(SourceLoc &WhereLoc,
SmallVectorImpl<Requirement> &Requirements); SmallVectorImpl<RequirementRepr> &Requirements);
}; };
} // end namespace swift } // end namespace swift

View File

@@ -126,6 +126,7 @@ struct ASTContext::Implementation {
}; };
llvm::DenseMap<Module*, ModuleType*> ModuleTypes; llvm::DenseMap<Module*, ModuleType*> ModuleTypes;
llvm::FoldingSet<GenericFunctionType> GenericFunctionTypes;
llvm::DenseMap<unsigned, BuiltinIntegerType*> IntegerTypes; llvm::DenseMap<unsigned, BuiltinIntegerType*> IntegerTypes;
llvm::FoldingSet<ProtocolCompositionType> ProtocolCompositionTypes; llvm::FoldingSet<ProtocolCompositionType> ProtocolCompositionTypes;
llvm::FoldingSet<BuiltinVectorType> BuiltinVectorTypes; llvm::FoldingSet<BuiltinVectorType> BuiltinVectorTypes;
@@ -1186,6 +1187,96 @@ PolymorphicFunctionType::PolymorphicFunctionType(Type input, Type output,
assert(!input->hasTypeVariable() && !output->hasTypeVariable()); assert(!input->hasTypeVariable() && !output->hasTypeVariable());
} }
void GenericFunctionType::Profile(llvm::FoldingSetNodeID &ID,
ArrayRef<GenericTypeParamType *> params,
ArrayRef<Requirement> requirements,
Type input,
Type result,
const ExtInfo &info) {
ID.AddInteger(params.size());
for (auto param : params)
ID.AddPointer(param);
ID.AddInteger(requirements.size());
for (const auto &req : requirements) {
ID.AddInteger(static_cast<unsigned>(req.getKind()));
ID.AddPointer(req.getFirstType().getPointer());
ID.AddPointer(req.getSecondType().getPointer());
}
ID.AddPointer(input.getPointer());
ID.AddPointer(result.getPointer());
ID.AddInteger(info.getFuncAttrKey());
}
GenericFunctionType *
GenericFunctionType::get(ArrayRef<GenericTypeParamType *> params,
ArrayRef<Requirement> requirements,
Type input,
Type output,
const ExtInfo &info,
const ASTContext &ctx) {
assert(!input->hasTypeVariable() && !output->hasTypeVariable());
llvm::FoldingSetNodeID id;
GenericFunctionType::Profile(id, params, requirements, input, output, info);
// Do we already have this generic function type?
void *insertPos;
if (auto result
= ctx.Impl.GenericFunctionTypes.FindNodeOrInsertPos(id, insertPos))
return result;
// We have to construct this generic function type. Determine whether
// it's canonical.
bool isCanonical = input->isCanonical() && output->isCanonical();
if (isCanonical) {
for (auto param : params) {
if (!param->isCanonical()) {
isCanonical = false;
break;
}
}
}
if (isCanonical ) {
for (const auto &req : requirements) {
if (!req.getFirstType()->isCanonical() ||
!req.getSecondType()->isCanonical()) {
isCanonical = false;
break;
}
}
}
// Allocate storage for the object.
size_t bytes = sizeof(GenericFunctionType)
+ sizeof(GenericTypeParamType *) * params.size()
+ sizeof(Requirement) * requirements.size();
void *mem = ctx.Allocate(bytes, alignof(GenericFunctionType));
auto result = new (mem) GenericFunctionType(params, requirements, input,
output, info,
isCanonical? &ctx : nullptr);
ctx.Impl.GenericFunctionTypes.InsertNode(result, insertPos);
return result;
}
GenericFunctionType::GenericFunctionType(
ArrayRef<GenericTypeParamType *> genericParams,
ArrayRef<Requirement> requirements,
Type input,
Type result,
const ExtInfo &info,
const ASTContext *ctx)
: AnyFunctionType(TypeKind::GenericFunction, ctx, input, result,
/*hasTypeVariable=*/false, info),
NumGenericParams(genericParams.size()),
NumRequirements(requirements.size())
{
std::copy(genericParams.begin(), genericParams.end(),
getGenericParamsBuffer().data());
std::copy(requirements.begin(), requirements.end(),
getRequirementsBuffer().data());
}
/// Return a uniqued array type with the specified base type and the /// Return a uniqued array type with the specified base type and the
/// specified size. /// specified size.
ArrayType *ArrayType::get(Type BaseType, uint64_t Size, const ASTContext &C) { ArrayType *ArrayType::get(Type BaseType, uint64_t Size, const ASTContext &C) {

View File

@@ -1116,6 +1116,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
case TypeKind::ArraySlice: case TypeKind::ArraySlice:
case TypeKind::Function: case TypeKind::Function:
case TypeKind::PolymorphicFunction: case TypeKind::PolymorphicFunction:
case TypeKind::GenericFunction:
OS << '('; OS << '(';
visit(T); visit(T);
OS << ')'; OS << ')';
@@ -1317,6 +1318,58 @@ public:
OS << " -> " << T->getResult(); OS << " -> " << T->getResult();
} }
void visitGenericFunctionType(GenericFunctionType *T) {
AttributePrinter Attrs(OS);
Attrs.printCC(T->getAbstractCC());
if (T->isThin())
Attrs.next() << "thin";
if (T->isNoReturn())
Attrs.next() << "noreturn";
Attrs.finish();
// Print the generic parameters.
OS << '<';
bool isFirstParam = true;
for (auto param : T->getGenericParams()) {
if (isFirstParam)
isFirstParam = false;
else
OS << ", ";
visit(param);
}
// Print the requirements.
bool isFirstReq = true;
for (const auto &req : T->getRequirements()) {
if (isFirstReq) {
OS << " where ";
isFirstReq = false;
} else {
OS << ", ";
}
visit(req.getFirstType());
switch (req.getKind()) {
case RequirementKind::Conformance:
OS << " : ";
break;
case RequirementKind::SameType:
OS << " == ";
break;
}
visit(req.getSecondType());
}
OS << '>';
OS << ' ';
printWithParensIfNotSimple(T->getInput());
OS << " -> " << T->getResult();
}
void visitArrayType(ArrayType *T) { void visitArrayType(ArrayType *T) {
printWithParensIfNotSimple(T->getBaseType()); printWithParensIfNotSimple(T->getBaseType());
OS << '[' << T->getSize() << ']'; OS << '[' << T->getSize() << ']';

View File

@@ -112,7 +112,7 @@ bool Decl::isTransparent() const {
GenericParamList::GenericParamList(SourceLoc LAngleLoc, GenericParamList::GenericParamList(SourceLoc LAngleLoc,
ArrayRef<GenericParam> Params, ArrayRef<GenericParam> Params,
SourceLoc WhereLoc, SourceLoc WhereLoc,
MutableArrayRef<Requirement> Requirements, MutableArrayRef<RequirementRepr> Requirements,
SourceLoc RAngleLoc) SourceLoc RAngleLoc)
: Brackets(LAngleLoc, RAngleLoc), NumParams(Params.size()), : Brackets(LAngleLoc, RAngleLoc), NumParams(Params.size()),
WhereLoc(WhereLoc), Requirements(Requirements), WhereLoc(WhereLoc), Requirements(Requirements),
@@ -129,7 +129,7 @@ GenericParamList *GenericParamList::create(ASTContext &Context,
+ sizeof(GenericParam) * Params.size(); + sizeof(GenericParam) * Params.size();
void *Mem = Context.Allocate(Size, alignof(GenericParamList)); void *Mem = Context.Allocate(Size, alignof(GenericParamList));
return new (Mem) GenericParamList(LAngleLoc, Params, SourceLoc(), return new (Mem) GenericParamList(LAngleLoc, Params, SourceLoc(),
MutableArrayRef<Requirement>(), MutableArrayRef<RequirementRepr>(),
RAngleLoc); RAngleLoc);
} }
@@ -138,7 +138,7 @@ GenericParamList::create(const ASTContext &Context,
SourceLoc LAngleLoc, SourceLoc LAngleLoc,
ArrayRef<GenericParam> Params, ArrayRef<GenericParam> Params,
SourceLoc WhereLoc, SourceLoc WhereLoc,
MutableArrayRef<Requirement> Requirements, MutableArrayRef<RequirementRepr> Requirements,
SourceLoc RAngleLoc) { SourceLoc RAngleLoc) {
unsigned Size = sizeof(GenericParamList) unsigned Size = sizeof(GenericParamList)
+ sizeof(GenericParam) * Params.size(); + sizeof(GenericParam) * Params.size();

View File

@@ -655,6 +655,10 @@ void Mangler::mangleType(CanType type, ExplosionKind explosion,
return; return;
} }
case TypeKind::GenericFunction: {
llvm_unreachable("cannot mangle generic function types yet");
}
case TypeKind::GenericTypeParam: { case TypeKind::GenericTypeParam: {
llvm_unreachable("cannot mangle generic type parameters yet"); llvm_unreachable("cannot mangle generic type parameters yet");
} }

View File

@@ -130,6 +130,7 @@ bool CanType::hasReferenceSemanticsImpl(CanType type) {
case TypeKind::BoundGenericClass: case TypeKind::BoundGenericClass:
case TypeKind::Function: case TypeKind::Function:
case TypeKind::PolymorphicFunction: case TypeKind::PolymorphicFunction:
case TypeKind::GenericFunction:
return true; return true;
case TypeKind::UnboundGeneric: case TypeKind::UnboundGeneric:
@@ -220,6 +221,9 @@ bool TypeBase::isUnspecializedGeneric() {
funcTy->getResult()->isUnspecializedGeneric(); funcTy->getResult()->isUnspecializedGeneric();
} }
case TypeKind::GenericFunction:
return true;
case TypeKind::Class: case TypeKind::Class:
case TypeKind::Struct: case TypeKind::Struct:
case TypeKind::Enum: case TypeKind::Enum:
@@ -623,6 +627,34 @@ CanType TypeBase::getCanonicalType() {
In->getASTContext()); In->getASTContext());
break; break;
} }
case TypeKind::GenericFunction: {
// Canonicalize generic parameters.
GenericFunctionType *function = cast<GenericFunctionType>(this);
SmallVector<GenericTypeParamType *, 4> genericParams;
for (auto param : function->getGenericParams()) {
auto newParam = param->getCanonicalType()->castTo<GenericTypeParamType>();
genericParams.push_back(newParam);
}
// Transform requirements.
SmallVector<Requirement, 4> requirements;
for (const auto &req : function->getRequirements()) {
auto firstType = req.getFirstType()->getCanonicalType();
auto secondType = req.getSecondType()->getCanonicalType();
requirements.push_back(Requirement(req.getKind(), firstType,
secondType));
}
// Transform input type.
auto inputTy = function->getInput()->getCanonicalType();
auto resultTy = function->getResult()->getCanonicalType();
Result = GenericFunctionType::get(genericParams, requirements, inputTy,
resultTy, function->getExtInfo(),
inputTy->getASTContext());
break;
}
case TypeKind::Function: { case TypeKind::Function: {
FunctionType *FT = cast<FunctionType>(this); FunctionType *FT = cast<FunctionType>(this);
Type In = FT->getInput()->getCanonicalType(); Type In = FT->getInput()->getCanonicalType();
@@ -693,6 +725,7 @@ TypeBase *TypeBase::getDesugaredType() {
case TypeKind::Tuple: case TypeKind::Tuple:
case TypeKind::Function: case TypeKind::Function:
case TypeKind::PolymorphicFunction: case TypeKind::PolymorphicFunction:
case TypeKind::GenericFunction:
case TypeKind::Array: case TypeKind::Array:
case TypeKind::LValue: case TypeKind::LValue:
case TypeKind::ProtocolComposition: case TypeKind::ProtocolComposition:
@@ -849,7 +882,8 @@ bool TypeBase::isSpelledLike(Type other) {
return true; return true;
} }
case TypeKind::PolymorphicFunction: { case TypeKind::PolymorphicFunction:
case TypeKind::GenericFunction: {
// Polymorphic function types should never be explicitly spelled. // Polymorphic function types should never be explicitly spelled.
return false; return false;
} }

View File

@@ -429,6 +429,12 @@ namespace {
return llvm::UndefValue::get(IGF.IGM.TypeMetadataPtrTy); return llvm::UndefValue::get(IGF.IGM.TypeMetadataPtrTy);
} }
llvm::Value *visitGenericFunctionType(CanGenericFunctionType type) {
IGF.unimplemented(SourceLoc(),
"metadata ref for generic function type");
return llvm::UndefValue::get(IGF.IGM.TypeMetadataPtrTy);
}
llvm::Value *visitFunctionType(CanFunctionType type) { llvm::Value *visitFunctionType(CanFunctionType type) {
if (auto metatype = tryGetLocal(type)) if (auto metatype = tryGetLocal(type))
return metatype; return metatype;

View File

@@ -648,6 +648,7 @@ TypeCacheEntry TypeConverter::convertType(CanType ty) {
return convertProtocolType(cast<ProtocolType>(ty)); return convertProtocolType(cast<ProtocolType>(ty));
case TypeKind::ProtocolComposition: case TypeKind::ProtocolComposition:
return convertProtocolCompositionType(cast<ProtocolCompositionType>(ty)); return convertProtocolCompositionType(cast<ProtocolCompositionType>(ty));
case TypeKind::GenericFunction:
case TypeKind::GenericTypeParam: case TypeKind::GenericTypeParam:
case TypeKind::DependentMember: case TypeKind::DependentMember:
llvm_unreachable("can't convert dependent type"); llvm_unreachable("can't convert dependent type");

View File

@@ -108,6 +108,7 @@ public:
->visitArchetypeType(cast<ArchetypeType>(origTy), ->visitArchetypeType(cast<ArchetypeType>(origTy),
substTy); substTy);
case TypeKind::GenericFunction:
case TypeKind::GenericTypeParam: case TypeKind::GenericTypeParam:
case TypeKind::DependentMember: case TypeKind::DependentMember:
// FIXME: This should duplicate, then subsume, the archetype path? // FIXME: This should duplicate, then subsume, the archetype path?

View File

@@ -89,7 +89,7 @@ GenericParamList *Parser::parseGenericParameters(SourceLoc LAngleLoc) {
// Parse the optional where-clause. // Parse the optional where-clause.
SourceLoc WhereLoc; SourceLoc WhereLoc;
SmallVector<Requirement, 4> Requirements; SmallVector<RequirementRepr, 4> Requirements;
if (Tok.is(tok::kw_where) && if (Tok.is(tok::kw_where) &&
parseGenericWhereClause(WhereLoc, Requirements)) { parseGenericWhereClause(WhereLoc, Requirements)) {
Invalid = true; Invalid = true;
@@ -146,8 +146,8 @@ GenericParamList *Parser::maybeParseGenericParams() {
/// same-type-requirement: /// same-type-requirement:
/// type-identifier '==' type-identifier /// type-identifier '==' type-identifier
bool Parser::parseGenericWhereClause(SourceLoc &WhereLoc, bool Parser::parseGenericWhereClause(SourceLoc &WhereLoc,
SmallVectorImpl<Requirement> &Requirements) { SmallVectorImpl<RequirementRepr> &Requirements) {
// Parse the 'requires'. // Parse the 'where'.
WhereLoc = consumeToken(tok::kw_where); WhereLoc = consumeToken(tok::kw_where);
bool Invalid = false; bool Invalid = false;
do { do {
@@ -176,7 +176,7 @@ bool Parser::parseGenericWhereClause(SourceLoc &WhereLoc,
} }
// Add the requirement. // Add the requirement.
Requirements.push_back(Requirement::getConformance(FirstType.get(), Requirements.push_back(RequirementRepr::getConformance(FirstType.get(),
ColonLoc, ColonLoc,
Protocol.get())); Protocol.get()));
} else if ((Tok.isAnyOperator() && Tok.getText() == "==") || } else if ((Tok.isAnyOperator() && Tok.getText() == "==") ||
@@ -196,7 +196,7 @@ bool Parser::parseGenericWhereClause(SourceLoc &WhereLoc,
} }
// Add the requirement // Add the requirement
Requirements.push_back(Requirement::getSameType(FirstType.get(), Requirements.push_back(RequirementRepr::getSameType(FirstType.get(),
EqualLoc, EqualLoc,
SecondType.get())); SecondType.get()));
} else { } else {

View File

@@ -143,7 +143,7 @@ CanAnyFunctionType TypeConverter::getUncurriedFunctionType(CanAnyFunctionType t,
// The uncurried generic parameter list components. // The uncurried generic parameter list components.
bool isPolymorphic = false; bool isPolymorphic = false;
SmallVector<GenericParam, 4> genericParams; SmallVector<GenericParam, 4> genericParams;
SmallVector<Requirement, 4> requirements; SmallVector<RequirementRepr, 4> requirements;
SmallVector<ArchetypeType *, 4> allArchetypes; SmallVector<ArchetypeType *, 4> allArchetypes;
GenericParamList *outerParameters = nullptr; GenericParamList *outerParameters = nullptr;

View File

@@ -114,7 +114,6 @@ auto ArchetypeBuilder::PotentialArchetype::getArchetype(
return nullptr; return nullptr;
// Find the protocol that has an associated type with this name. // Find the protocol that has an associated type with this name.
llvm::SmallSetVector<AssociatedTypeDecl *, 2> assocTypes;
for (auto proto : ParentArchetype->getConformsTo()) { for (auto proto : ParentArchetype->getConformsTo()) {
SmallVector<ValueDecl *, 2> decls; SmallVector<ValueDecl *, 2> decls;
if (tu.lookupQualified(proto->getDeclaredType(), Name, if (tu.lookupQualified(proto->getDeclaredType(), Name,
@@ -156,6 +155,23 @@ auto ArchetypeBuilder::PotentialArchetype::getArchetype(
return Archetype; return Archetype;
} }
AssociatedTypeDecl *
ArchetypeBuilder::PotentialArchetype::getAssociatedType(TranslationUnit &tu,
Identifier name) {
for (auto proto : getRepresentative()->getConformsTo()) {
SmallVector<ValueDecl *, 2> decls;
if (tu.lookupQualified(proto->getDeclaredType(), name,
NL_VisitSupertypes, nullptr, decls)) {
for (auto decl : decls) {
if (auto assocType = dyn_cast<AssociatedTypeDecl>(decl))
return assocType;
}
}
}
return nullptr;
}
void ArchetypeBuilder::PotentialArchetype::dump(llvm::raw_ostream &Out, void ArchetypeBuilder::PotentialArchetype::dump(llvm::raw_ostream &Out,
unsigned Indent) { unsigned Indent) {
// Print name. // Print name.
@@ -397,7 +413,7 @@ bool ArchetypeBuilder::addSameTypeRequirement(PotentialArchetype *T1,
return false; return false;
} }
bool ArchetypeBuilder::addRequirement(const Requirement &Req) { bool ArchetypeBuilder::addRequirement(const RequirementRepr &Req) {
switch (Req.getKind()) { switch (Req.getKind()) {
case RequirementKind::Conformance: { case RequirementKind::Conformance: {
PotentialArchetype *PA = resolveType(Req.getSubject()); PotentialArchetype *PA = resolveType(Req.getSubject());

View File

@@ -1715,6 +1715,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, TypeMatchKind kind,
} }
case TypeKind::PolymorphicFunction: case TypeKind::PolymorphicFunction:
case TypeKind::GenericFunction:
llvm_unreachable("Polymorphic function type should have been opened"); llvm_unreachable("Polymorphic function type should have been opened");
case TypeKind::Array: { case TypeKind::Array: {
@@ -2239,6 +2240,7 @@ ConstraintSystem::simplifyConstructionConstraint(Type valueType, Type argType,
case TypeKind::Error: case TypeKind::Error:
return SolutionKind::Error; return SolutionKind::Error;
case TypeKind::GenericFunction:
case TypeKind::GenericTypeParam: case TypeKind::GenericTypeParam:
case TypeKind::DependentMember: case TypeKind::DependentMember:
llvm_unreachable("unmapped dependent type"); llvm_unreachable("unmapped dependent type");

View File

@@ -199,7 +199,13 @@ static void validateAttributes(TypeChecker &TC, Decl *VD);
/// This routine validates all of the types in the parsed inheritance clause, /// This routine validates all of the types in the parsed inheritance clause,
/// recording the superclass (if any and if allowed) as well as the protocols /// recording the superclass (if any and if allowed) as well as the protocols
/// to which this type declaration conforms. /// to which this type declaration conforms.
static void checkInheritanceClause(TypeChecker &tc, Decl *decl) { void TypeChecker::checkInheritanceClause(Decl *decl,
GenericTypeResolver *resolver) {
// Establish a default generic type resolver.
PartialGenericTypeToArchetypeResolver defaultResolver(*this);
if (!resolver)
resolver = &defaultResolver;
MutableArrayRef<TypeLoc> inheritedClause; MutableArrayRef<TypeLoc> inheritedClause;
// If we already checked the inheritance clause, don't do so again. // If we already checked the inheritance clause, don't do so again.
@@ -225,13 +231,13 @@ static void checkInheritanceClause(TypeChecker &tc, Decl *decl) {
SourceRange superclassRange; SourceRange superclassRange;
llvm::SmallSetVector<ProtocolDecl *, 4> allProtocols; llvm::SmallSetVector<ProtocolDecl *, 4> allProtocols;
llvm::SmallDenseMap<CanType, SourceRange> inheritedTypes; llvm::SmallDenseMap<CanType, SourceRange> inheritedTypes;
addImplicitConformances(tc, decl, allProtocols); addImplicitConformances(*this, decl, allProtocols);
for (unsigned i = 0, n = inheritedClause.size(); i != n; ++i) { for (unsigned i = 0, n = inheritedClause.size(); i != n; ++i) {
auto &inherited = inheritedClause[i]; auto &inherited = inheritedClause[i];
// Validate the type. // Validate the type.
if (tc.validateType(inherited)) { if (validateType(inherited, /*allowUnboundGenerics=*/false, resolver)) {
inherited.setInvalidType(tc.Context); inherited.setInvalidType(Context);
continue; continue;
} }
@@ -242,14 +248,14 @@ static void checkInheritanceClause(TypeChecker &tc, Decl *decl) {
auto knownType = inheritedTypes.find(inheritedCanTy); auto knownType = inheritedTypes.find(inheritedCanTy);
if (knownType != inheritedTypes.end()) { if (knownType != inheritedTypes.end()) {
SourceLoc afterPriorLoc SourceLoc afterPriorLoc
= Lexer::getLocForEndOfToken(tc.Context.SourceMgr, = Lexer::getLocForEndOfToken(Context.SourceMgr,
inheritedClause[i-1].getSourceRange().End); inheritedClause[i-1].getSourceRange().End);
SourceLoc afterMyEndLoc SourceLoc afterMyEndLoc
= Lexer::getLocForEndOfToken(tc.Context.SourceMgr, = Lexer::getLocForEndOfToken(Context.SourceMgr,
inherited.getSourceRange().End); inherited.getSourceRange().End);
tc.diagnose(inherited.getSourceRange().Start, diagnose(inherited.getSourceRange().Start,
diag::duplicate_inheritance, inheritedTy) diag::duplicate_inheritance, inheritedTy)
.fixItRemoveChars(afterPriorLoc, afterMyEndLoc) .fixItRemoveChars(afterPriorLoc, afterMyEndLoc)
.highlight(knownType->second); .highlight(knownType->second);
continue; continue;
@@ -263,8 +269,8 @@ static void checkInheritanceClause(TypeChecker &tc, Decl *decl) {
if (auto protoTy = inheritedTy->getAs<ProtocolType>()) { if (auto protoTy = inheritedTy->getAs<ProtocolType>()) {
if (protoTy->getDecl()->isSpecificProtocol( if (protoTy->getDecl()->isSpecificProtocol(
KnownProtocolKind::DynamicLookup)) { KnownProtocolKind::DynamicLookup)) {
tc.diagnose(inheritedClause[i].getSourceRange().Start, diagnose(inheritedClause[i].getSourceRange().Start,
diag::dynamic_lookup_conformance); diag::dynamic_lookup_conformance);
continue; continue;
} }
} }
@@ -279,8 +285,8 @@ static void checkInheritanceClause(TypeChecker &tc, Decl *decl) {
if (isa<EnumDecl>(decl)) { if (isa<EnumDecl>(decl)) {
// Check if we already had a raw type. // Check if we already had a raw type.
if (superclassTy) { if (superclassTy) {
tc.diagnose(inherited.getSourceRange().Start, diagnose(inherited.getSourceRange().Start,
diag::multiple_enum_raw_types, superclassTy, inheritedTy) diag::multiple_enum_raw_types, superclassTy, inheritedTy)
.highlight(superclassRange); .highlight(superclassRange);
continue; continue;
} }
@@ -289,14 +295,14 @@ static void checkInheritanceClause(TypeChecker &tc, Decl *decl) {
if (i > 0) { if (i > 0) {
SourceLoc afterPriorLoc SourceLoc afterPriorLoc
= Lexer::getLocForEndOfToken( = Lexer::getLocForEndOfToken(
tc.Context.SourceMgr, Context.SourceMgr,
inheritedClause[i-1].getSourceRange().End); inheritedClause[i-1].getSourceRange().End);
SourceLoc afterMyEndLoc SourceLoc afterMyEndLoc
= Lexer::getLocForEndOfToken(tc.Context.SourceMgr, = Lexer::getLocForEndOfToken(Context.SourceMgr,
inherited.getSourceRange().End); inherited.getSourceRange().End);
tc.diagnose(inherited.getSourceRange().Start, diagnose(inherited.getSourceRange().Start,
diag::raw_type_not_first, inheritedTy) diag::raw_type_not_first, inheritedTy)
.fixItRemoveChars(afterPriorLoc, afterMyEndLoc) .fixItRemoveChars(afterPriorLoc, afterMyEndLoc)
.fixItInsert(inheritedClause[0].getSourceRange().Start, .fixItInsert(inheritedClause[0].getSourceRange().Start,
inheritedTy.getString() + ", "); inheritedTy.getString() + ", ");
@@ -318,8 +324,8 @@ static void checkInheritanceClause(TypeChecker &tc, Decl *decl) {
// Complain about multiple inheritance. // Complain about multiple inheritance.
// Don't emit a Fix-It here. The user has to think harder about this. // Don't emit a Fix-It here. The user has to think harder about this.
tc.diagnose(inherited.getSourceRange().Start, diagnose(inherited.getSourceRange().Start,
diag::multiple_inheritance, superclassTy, inheritedTy) diag::multiple_inheritance, superclassTy, inheritedTy)
.highlight(superclassRange); .highlight(superclassRange);
continue; continue;
} }
@@ -330,11 +336,11 @@ static void checkInheritanceClause(TypeChecker &tc, Decl *decl) {
// FIXME: Allow type aliases to 'inherit' from classes, as an additional // FIXME: Allow type aliases to 'inherit' from classes, as an additional
// kind of requirement? // kind of requirement?
if (!canInheritClass(decl)) { if (!canInheritClass(decl)) {
tc.diagnose(decl->getLoc(), diagnose(decl->getLoc(),
isa<ExtensionDecl>(decl) isa<ExtensionDecl>(decl)
? diag::extension_class_inheritance ? diag::extension_class_inheritance
: diag::non_class_inheritance, : diag::non_class_inheritance,
getDeclaredType(decl), inheritedTy) getDeclaredType(decl), inheritedTy)
.highlight(inherited.getSourceRange()); .highlight(inherited.getSourceRange());
continue; continue;
} }
@@ -343,14 +349,14 @@ static void checkInheritanceClause(TypeChecker &tc, Decl *decl) {
if (i > 0) { if (i > 0) {
SourceLoc afterPriorLoc SourceLoc afterPriorLoc
= Lexer::getLocForEndOfToken( = Lexer::getLocForEndOfToken(
tc.Context.SourceMgr, Context.SourceMgr,
inheritedClause[i-1].getSourceRange().End); inheritedClause[i-1].getSourceRange().End);
SourceLoc afterMyEndLoc SourceLoc afterMyEndLoc
= Lexer::getLocForEndOfToken(tc.Context.SourceMgr, = Lexer::getLocForEndOfToken(Context.SourceMgr,
inherited.getSourceRange().End); inherited.getSourceRange().End);
tc.diagnose(inherited.getSourceRange().Start, diagnose(inherited.getSourceRange().Start,
diag::superclass_not_first, inheritedTy) diag::superclass_not_first, inheritedTy)
.fixItRemoveChars(afterPriorLoc, afterMyEndLoc) .fixItRemoveChars(afterPriorLoc, afterMyEndLoc)
.fixItInsert(inheritedClause[0].getSourceRange().Start, .fixItInsert(inheritedClause[0].getSourceRange().Start,
inheritedTy.getString() + ", "); inheritedTy.getString() + ", ");
@@ -369,11 +375,11 @@ static void checkInheritanceClause(TypeChecker &tc, Decl *decl) {
continue; continue;
// We can't inherit from a non-class, non-protocol type. // We can't inherit from a non-class, non-protocol type.
tc.diagnose(decl->getLoc(), diagnose(decl->getLoc(),
canInheritClass(decl) canInheritClass(decl)
? diag::inheritance_from_non_protocol_or_class ? diag::inheritance_from_non_protocol_or_class
: diag::inheritance_from_non_protocol, : diag::inheritance_from_non_protocol,
inheritedTy); inheritedTy);
// FIXME: Note pointing to the declaration 'inheritedTy' references? // FIXME: Note pointing to the declaration 'inheritedTy' references?
} }
@@ -382,7 +388,7 @@ static void checkInheritanceClause(TypeChecker &tc, Decl *decl) {
if (allProtocols.empty() && !superclassTy) if (allProtocols.empty() && !superclassTy)
return; return;
auto allProtocolsCopy = tc.Context.AllocateCopy(allProtocols); auto allProtocolsCopy = Context.AllocateCopy(allProtocols);
if (auto ext = dyn_cast<ExtensionDecl>(decl)) { if (auto ext = dyn_cast<ExtensionDecl>(decl)) {
assert(!superclassTy && "Extensions can't add superclasses"); assert(!superclassTy && "Extensions can't add superclasses");
ext->setProtocols(allProtocolsCopy); ext->setProtocols(allProtocolsCopy);
@@ -407,7 +413,7 @@ static void checkInheritanceClause(TypeChecker &tc, Decl *decl) {
unsigned conformancesSize unsigned conformancesSize
= sizeof(ProtocolConformance *) * allProtocols.size(); = sizeof(ProtocolConformance *) * allProtocols.size();
ProtocolConformance **conformances ProtocolConformance **conformances
= (ProtocolConformance **)tc.Context.Allocate( = (ProtocolConformance **)Context.Allocate(
conformancesSize, conformancesSize,
alignof(ProtocolConformance *)); alignof(ProtocolConformance *));
memset(conformances, 0, conformancesSize); memset(conformances, 0, conformancesSize);
@@ -427,7 +433,7 @@ static ArrayRef<ProtocolDecl *> getInheritedForCycleCheck(TypeChecker &tc,
static ArrayRef<ClassDecl *> getInheritedForCycleCheck(TypeChecker &tc, static ArrayRef<ClassDecl *> getInheritedForCycleCheck(TypeChecker &tc,
ClassDecl *classDecl, ClassDecl *classDecl,
ClassDecl **scratch) { ClassDecl **scratch) {
checkInheritanceClause(tc, classDecl); tc.checkInheritanceClause(classDecl);
if (classDecl->hasSuperclass()) { if (classDecl->hasSuperclass()) {
*scratch = classDecl->getSuperclass()->getClassOrBoundGenericClass(); *scratch = classDecl->getSuperclass()->getClassOrBoundGenericClass();
@@ -440,7 +446,7 @@ static ArrayRef<ClassDecl *> getInheritedForCycleCheck(TypeChecker &tc,
static ArrayRef<EnumDecl *> getInheritedForCycleCheck(TypeChecker &tc, static ArrayRef<EnumDecl *> getInheritedForCycleCheck(TypeChecker &tc,
EnumDecl *enumDecl, EnumDecl *enumDecl,
EnumDecl **scratch) { EnumDecl **scratch) {
checkInheritanceClause(tc, enumDecl); tc.checkInheritanceClause(enumDecl);
if (enumDecl->hasRawType()) { if (enumDecl->hasRawType()) {
*scratch = enumDecl->getRawType()->getEnumOrBoundGenericEnum(); *scratch = enumDecl->getRawType()->getEnumOrBoundGenericEnum();
@@ -585,7 +591,8 @@ static CanType getExtendedType(ExtensionDecl *ED) {
return ExtendedTy; return ExtendedTy;
} }
/// Create a fresh archetype building. /// Create a fresh archetype builder.
/// FIXME: Duplicated with TypeCheckGeneric.cpp; this one should go away.
static ArchetypeBuilder createArchetypeBuilder(TypeChecker &TC) { static ArchetypeBuilder createArchetypeBuilder(TypeChecker &TC) {
return ArchetypeBuilder( return ArchetypeBuilder(
TC.TU, TC.Diags, TC.TU, TC.Diags,
@@ -593,13 +600,11 @@ static ArchetypeBuilder createArchetypeBuilder(TypeChecker &TC) {
return TC.getDirectConformsTo(protocol); return TC.getDirectConformsTo(protocol);
}, },
[&](AbstractTypeParamDecl *assocType) -> ArrayRef<ProtocolDecl *> { [&](AbstractTypeParamDecl *assocType) -> ArrayRef<ProtocolDecl *> {
checkInheritanceClause(TC, assocType); TC.checkInheritanceClause(assocType);
return assocType->getProtocols(); return assocType->getProtocols();
}); });
} }
/// Revert the given dependently-typed TypeLoc to a state where generic
/// parameters have not yet been resolved.
static void revertDependentTypeLoc(TypeLoc &tl, DeclContext *dc) { static void revertDependentTypeLoc(TypeLoc &tl, DeclContext *dc) {
// Make sure we validate the type again. // Make sure we validate the type again.
tl.setType(Type(), /*validated=*/false); tl.setType(Type(), /*validated=*/false);
@@ -663,9 +668,7 @@ static void revertDependentTypeLoc(TypeLoc &tl, DeclContext *dc) {
tl.getTypeRepr()->walk(RevertWalker(dc)); tl.getTypeRepr()->walk(RevertWalker(dc));
} }
/// Revert the dependently-typed TypeLocs within the given pattern to a static void revertDependentPattern(Pattern *pattern, DeclContext *dc) {
/// state where generic parameters have not yet been resolved.
void revertDependentPattern(Pattern *pattern, DeclContext *dc) {
// Clear out the pattern's type. // Clear out the pattern's type.
if (pattern->hasType()) if (pattern->hasType())
pattern->overwriteType(Type()); pattern->overwriteType(Type());
@@ -718,9 +721,9 @@ void revertDependentPattern(Pattern *pattern, DeclContext *dc) {
/// Check the given generic parameter list, introduce the generic parameters /// Check the given generic parameter list, introduce the generic parameters
/// and requirements into the archetype builder, but don't assign archetypes /// and requirements into the archetype builder, but don't assign archetypes
/// yet. /// yet.
void checkGenericParamList(ArchetypeBuilder &builder, static void checkGenericParamList(ArchetypeBuilder &builder,
GenericParamList *genericParams, GenericParamList *genericParams,
TypeChecker &TC) { TypeChecker &TC) {
assert(genericParams && "Missing generic parameters"); assert(genericParams && "Missing generic parameters");
unsigned Depth = genericParams->getDepth(); unsigned Depth = genericParams->getDepth();
@@ -733,7 +736,7 @@ void checkGenericParamList(ArchetypeBuilder &builder,
TypeParam->setDepth(Depth); TypeParam->setDepth(Depth);
// Check the constraints on the type parameter. // Check the constraints on the type parameter.
checkInheritanceClause(TC, TypeParam); TC.checkInheritanceClause(TypeParam);
// Add the generic parameter to the builder. // Add the generic parameter to the builder.
builder.addGenericParameter(TypeParam, Index++); builder.addGenericParameter(TypeParam, Index++);
@@ -805,12 +808,46 @@ void checkGenericParamList(ArchetypeBuilder &builder,
} }
} }
/// Revert the dependent types within the given generic parameter list.
static void revertGenericParamList(GenericParamList *genericParams,
DeclContext *dc) {
// FIXME: Revert the inherited clause of the generic parameter list.
#if 0
for (auto param : *genericParams) {
auto typeParam = param.getAsTypeParam();
typeParam->setCheckedInheritanceClause(false);
for (auto &inherited : typeParam->getInherited())
revertDependentTypeLoc(inherited, dc);
}
#endif
// Revert the requirements of the generic parameter list.
for (auto &req : genericParams->getRequirements()) {
if (req.isInvalid())
continue;
switch (req.getKind()) {
case RequirementKind::Conformance: {
revertDependentTypeLoc(req.getSubjectLoc(), dc);
revertDependentTypeLoc(req.getConstraintLoc(), dc);
break;
}
case RequirementKind::SameType:
revertDependentTypeLoc(req.getFirstTypeLoc(), dc);
revertDependentTypeLoc(req.getSecondTypeLoc(), dc);
break;
}
}
}
/// Finalize the given generic parameter list, assigning archetypes to /// Finalize the given generic parameter list, assigning archetypes to
/// the generic parameters. /// the generic parameters.
void finalizeGenericParamList(ArchetypeBuilder &builder, static void finalizeGenericParamList(ArchetypeBuilder &builder,
GenericParamList *genericParams, GenericParamList *genericParams,
DeclContext *dc, DeclContext *dc,
TypeChecker &TC) { TypeChecker &TC) {
// Wire up the archetypes. // Wire up the archetypes.
builder.assignArchetypes(); builder.assignArchetypes();
for (auto GP : *genericParams) { for (auto GP : *genericParams) {
@@ -861,6 +898,34 @@ void finalizeGenericParamList(ArchetypeBuilder &builder,
} }
} }
void TypeChecker::revertGenericFuncSignature(FuncDecl *func) {
// Revert the result type.
if (!func->getBodyResultTypeLoc().isNull()) {
revertDependentTypeLoc(func->getBodyResultTypeLoc(), func);
}
// Revert the argument patterns.
ArrayRef<Pattern *> argPatterns = func->getArgParamPatterns();
if (func->getDeclContext()->isTypeContext())
argPatterns = argPatterns.slice(1);
for (auto argPattern : argPatterns) {
revertDependentPattern(argPattern, func);
}
// Revert the body patterns.
ArrayRef<Pattern *> bodyPatterns = func->getBodyParamPatterns();
if (func->getDeclContext()->isTypeContext())
bodyPatterns = bodyPatterns.slice(1);
for (auto bodyPattern : bodyPatterns) {
revertDependentPattern(bodyPattern, func);
}
// Revert the generic parameter list.
revertGenericParamList(func->getGenericParams(), func);
// Clear out the types.
func->revertType();
}
namespace { namespace {
@@ -1077,7 +1142,7 @@ public:
} }
if (!isa<ProtocolDecl>(TAD->getDeclContext())) if (!isa<ProtocolDecl>(TAD->getDeclContext()))
checkInheritanceClause(TC, TAD); TC.checkInheritanceClause(TAD);
} }
if (!IsFirstPass) if (!IsFirstPass)
@@ -1551,69 +1616,33 @@ public:
} }
} }
Optional<ArchetypeBuilder> builder; bool isInvalid = false;
// If we have generic parameters, check the generic signature now.
if (auto gp = FD->getGenericParams()) { if (auto gp = FD->getGenericParams()) {
gp->setOuterParameters(outerGenericParams); gp->setOuterParameters(outerGenericParams);
builder.emplace(createArchetypeBuilder(TC));
checkGenericParamList(*builder, gp, TC);
}
// If we have generic parameters, create archetypes now. if (TC.validateGenericFuncSignature(FD))
bool isInvalid = false;
if (builder) {
// Type check the function declaration.
PartialGenericTypeToArchetypeResolver resolver(TC);
semaFuncDecl(FD, /*consumeAttributes=*/false, &resolver);
// Infer requirements from the parameters of the function.
for (auto pattern : FD->getArgParamPatterns()) {
builder->inferRequirements(pattern);
}
// Infer requirements from the result type.
if (auto resultType = FD->getBodyResultTypeLoc().getTypeRepr())
builder->inferRequirements(resultType);
// Revert all of the types within the signature of the
auto revertSignature = [&]() {
// Revert the result type.
if (!FD->getBodyResultTypeLoc().isNull()) {
revertDependentTypeLoc(FD->getBodyResultTypeLoc(), FD);
}
// Revert the argument patterns.
ArrayRef<Pattern *> argPatterns = FD->getArgParamPatterns();
if (FD->getDeclContext()->isTypeContext())
argPatterns = argPatterns.slice(1);
for (auto argPattern : argPatterns) {
revertDependentPattern(argPattern, FD);
}
// Revert the body patterns.
ArrayRef<Pattern *> bodyPatterns = FD->getBodyParamPatterns();
if (FD->getDeclContext()->isTypeContext())
bodyPatterns = bodyPatterns.slice(1);
for (auto bodyPattern : bodyPatterns) {
revertDependentPattern(bodyPattern, FD);
}
// Clear out the types.
FD->revertType();
};
// Go through and revert all of the dependent types we computed.
revertSignature();
// Completely resolve the generic signature.
CompleteGenericTypeResolver completeResolver(TC, *builder);
semaFuncDecl(FD, /*consumeAttributes=*/false, &completeResolver);
if (FD->getType()->is<ErrorType>()) {
isInvalid = true; isInvalid = true;
} else { else {
// Assign archetypes... after reverting the signature once again. // Create a fresh archetype builder.
revertSignature(); ArchetypeBuilder builder = createArchetypeBuilder(TC);
finalizeGenericParamList(*builder, FD->getGenericParams(), FD, TC); checkGenericParamList(builder, gp, TC);
// Infer requirements from parameter patterns.
for (auto pattern : FD->getArgParamPatterns()) {
builder.inferRequirements(pattern);
}
// Infer requirements from the result type.
if (!FD->getBodyResultTypeLoc().isNull()) {
builder.inferRequirements(FD->getBodyResultTypeLoc().getTypeRepr());
}
// Revert all of the types within the signature of the function.
TC.revertGenericFuncSignature(FD);
finalizeGenericParamList(builder, FD->getGenericParams(), FD, TC);
} }
} }
@@ -1745,7 +1774,7 @@ public:
ED->setInvalid(); ED->setInvalid();
} }
checkInheritanceClause(TC, ED); TC.checkInheritanceClause(ED);
if (auto nominal = ExtendedTy->getAnyNominal()) if (auto nominal = ExtendedTy->getAnyNominal())
TC.validateDecl(nominal); TC.validateDecl(nominal);
@@ -1973,7 +2002,7 @@ void TypeChecker::validateDecl(ValueDecl *D, bool resolveTypeParams) {
case DeclKind::Class: { case DeclKind::Class: {
auto nominal = cast<NominalTypeDecl>(D); auto nominal = cast<NominalTypeDecl>(D);
for (auto ext : nominal->getExtensions()) for (auto ext : nominal->getExtensions())
checkInheritanceClause(*this, ext); checkInheritanceClause(ext);
if (nominal->hasType()) if (nominal->hasType())
return; return;
@@ -1992,7 +2021,7 @@ void TypeChecker::validateDecl(ValueDecl *D, bool resolveTypeParams) {
nominal->computeType(); nominal->computeType();
validateAttributes(*this, D); validateAttributes(*this, D);
checkInheritanceClause(*this, D); checkInheritanceClause(D);
// Mark a class as [objc]. This must happen before checking its members. // Mark a class as [objc]. This must happen before checking its members.
if (auto CD = dyn_cast<ClassDecl>(nominal)) { if (auto CD = dyn_cast<ClassDecl>(nominal)) {
@@ -2019,14 +2048,14 @@ void TypeChecker::validateDecl(ValueDecl *D, bool resolveTypeParams) {
return; return;
proto->computeType(); proto->computeType();
checkInheritanceClause(*this, D); checkInheritanceClause(D);
validateAttributes(*this, D); validateAttributes(*this, D);
// Fix the 'Self' associated type. // Fix the 'Self' associated type.
AssociatedTypeDecl *selfDecl = nullptr; AssociatedTypeDecl *selfDecl = nullptr;
for (auto member : proto->getMembers()) { for (auto member : proto->getMembers()) {
if (auto AssocType = dyn_cast<AssociatedTypeDecl>(member)) { if (auto AssocType = dyn_cast<AssociatedTypeDecl>(member)) {
checkInheritanceClause(*this, AssocType); checkInheritanceClause(AssocType);
if (AssocType->isSelf()) { if (AssocType->isSelf()) {
selfDecl = AssocType; selfDecl = AssocType;
@@ -2119,13 +2148,13 @@ void TypeChecker::validateDecl(ValueDecl *D, bool resolveTypeParams) {
ArrayRef<ProtocolDecl *> ArrayRef<ProtocolDecl *>
TypeChecker::getDirectConformsTo(NominalTypeDecl *nominal) { TypeChecker::getDirectConformsTo(NominalTypeDecl *nominal) {
checkInheritanceClause(*this, nominal); checkInheritanceClause(nominal);
return nominal->getProtocols(); return nominal->getProtocols();
} }
ArrayRef<ProtocolDecl *> ArrayRef<ProtocolDecl *>
TypeChecker::getDirectConformsTo(ExtensionDecl *ext) { TypeChecker::getDirectConformsTo(ExtensionDecl *ext) {
checkInheritanceClause(*this, ext); checkInheritanceClause(ext);
return ext->getProtocols(); return ext->getProtocols();
} }
@@ -2388,6 +2417,7 @@ bool TypeChecker::isDefaultInitializable(Type ty, Expr **initializer,
return true; return true;
} }
case TypeKind::GenericFunction:
case TypeKind::GenericTypeParam: case TypeKind::GenericTypeParam:
case TypeKind::DependentMember: case TypeKind::DependentMember:
llvm_unreachable("Should never ask about dependent types"); llvm_unreachable("Should never ask about dependent types");

View File

@@ -130,6 +130,356 @@ Type CompleteGenericTypeResolver::resolveDependentMemberType(
return ErrorType::get(TC.Context); return ErrorType::get(TC.Context);
} }
/// Create a fresh archetype builder.
static ArchetypeBuilder createArchetypeBuilder(TypeChecker &TC) {
return ArchetypeBuilder(
TC.TU, TC.Diags,
[&](ProtocolDecl *protocol) -> ArrayRef<ProtocolDecl *> {
return TC.getDirectConformsTo(protocol);
},
[&](AbstractTypeParamDecl *assocType) -> ArrayRef<ProtocolDecl *> {
TC.checkInheritanceClause(assocType);
return assocType->getProtocols();
});
}
/// Check the generic parameters in the given generic parameter list (and its
/// parent generic parameter lists) according to the given resolver.
static void checkGenericParameters(TypeChecker &tc, ArchetypeBuilder *builder,
GenericParamList *genericParams,
GenericTypeResolver &resolver,
bool innermost = true) {
// If there are outer generic parameters, visit them (so that the archetype
// builder knows about them) but don't modify them in any way.
// FIXME: Rather than crawling the generic outer parameters, it would be far
// better to simply grab the generic parameters and requirements for the
// outer context directly. However, we don't currently store those anywhere.
if (auto outerGenericParams = genericParams->getOuterParameters())
checkGenericParameters(tc, builder, outerGenericParams, resolver,
/*innermost=*/false);
// Visit each of the generic parameters.
unsigned depth = genericParams->getDepth();
unsigned index = 0;
for (auto param : *genericParams) {
auto typeParam = param.getAsTypeParam();
// Check the generic type parameter.
if (innermost) {
// Set the depth of this type parameter.
typeParam->setDepth(depth);
// Check the inheritance clause of this type parameter.
tc.checkInheritanceClause(typeParam, &resolver);
}
if (builder) {
// Add the generic parameter to the builder.
builder->addGenericParameter(typeParam, index++);
// Infer requirements from the inherited types.
// FIXME: This doesn't actually do what we want for outer generic
// parameters, because they've been resolved to archetypes too eagerly.
for (const auto &inherited : typeParam->getInherited()) {
builder->inferRequirements(inherited.getTypeRepr());
}
}
}
// Visit each of the requirements, adding them to the builder.
// Add the requirements clause to the builder, validating the types in
// the requirements clause along the way.
for (auto &req : genericParams->getRequirements()) {
if (req.isInvalid())
continue;
switch (req.getKind()) {
case RequirementKind::Conformance: {
// Validate the types.
if (tc.validateType(req.getSubjectLoc(),
/*allowUnboundGenerics=*/false,
&resolver)) {
req.setInvalid();
continue;
}
if (tc.validateType(req.getConstraintLoc(),
/*allowUnboundGenerics=*/false,
&resolver)) {
req.setInvalid();
continue;
}
// FIXME: Feels too early to perform this check.
if (!req.getConstraint()->isExistentialType() &&
!req.getConstraint()->getClassOrBoundGenericClass()) {
tc.diagnose(genericParams->getWhereLoc(),
diag::requires_conformance_nonprotocol,
req.getSubjectLoc(), req.getConstraintLoc());
req.getConstraintLoc().setInvalidType(tc.Context);
req.setInvalid();
continue;
}
// DynamicLookup cannot be used in a generic constraint.
if (auto protoTy = req.getConstraint()->getAs<ProtocolType>()) {
if (protoTy->getDecl()->isSpecificProtocol(
KnownProtocolKind::DynamicLookup)) {
tc.diagnose(req.getConstraintLoc().getSourceRange().Start,
diag::dynamic_lookup_conformance);
continue;
}
}
break;
}
case RequirementKind::SameType:
if (tc.validateType(req.getFirstTypeLoc(),
/*allowUnboundGenerics=*/false,
&resolver)) {
req.setInvalid();
continue;
}
if (tc.validateType(req.getSecondTypeLoc(),
/*allowUnboundGenerics=*/false,
&resolver)) {
req.setInvalid();
continue;
}
break;
}
if (builder && builder->addRequirement(req))
req.setInvalid();
}
}
/// Collect all of the generic parameter types at every level in the generic
/// parameter list.
static void collectGenericParamTypes(
GenericParamList *genericParams,
SmallVectorImpl<GenericTypeParamType *> &allParams) {
if (!genericParams)
return;
// Collect outer generic parameters first.
collectGenericParamTypes(genericParams->getOuterParameters(), allParams);
// Add our parameters.
for (auto param : *genericParams) {
allParams.push_back(param.getAsTypeParam()->getDeclaredType()
->castTo<GenericTypeParamType>());
}
}
namespace {
/// \brief Function object that orders potential archetypes by name.
struct OrderPotentialArchetypeByName {
using PotentialArchetype = ArchetypeBuilder::PotentialArchetype;
bool operator()(std::pair<Identifier, PotentialArchetype *> X,
std::pair<Identifier, PotentialArchetype *> Y) const {
return X.first.str() < Y.second->getName().str();
}
bool operator()(std::pair<Identifier, PotentialArchetype *> X,
Identifier Y) const {
return X.first.str() < Y.str();
}
bool operator()(Identifier X,
std::pair<Identifier, PotentialArchetype *> Y) const {
return X.str() < Y.first.str();
}
bool operator()(Identifier X, Identifier Y) const {
return X.str() < Y.str();
}
};
}
/// Add the requirements for the given potential archetype and its nested
/// potential archetypes to the set of requirements.
static void
addRequirements(
TranslationUnit &tu, Type type,
ArchetypeBuilder::PotentialArchetype *pa,
llvm::SmallPtrSet<ArchetypeBuilder::PotentialArchetype *, 16> &knownPAs,
SmallVectorImpl<Requirement> &requirements) {
using PotentialArchetype = ArchetypeBuilder::PotentialArchetype;
// Add superclass requirement, if needed.
if (auto superclass = pa->getSuperclass()) {
// FIXME: Distinguish superclass from conformance?
// FIXME: What if the superclass type involves a type parameter?
requirements.push_back(Requirement(RequirementKind::Conformance,
type, superclass));
}
// Add conformance requirements.
for (auto proto : pa->getConformsTo()) {
requirements.push_back(Requirement(RequirementKind::Conformance,
type, proto->getDeclaredType()));
}
// Collect the nested types, sorted by name.
// FIXME: Could collect these from the conformance requirements, above.
SmallVector<std::pair<Identifier, PotentialArchetype*>, 16>
nestedTypes(pa->getNestedTypes().begin(), pa->getNestedTypes().end());
std::sort(nestedTypes.begin(), nestedTypes.end(),
OrderPotentialArchetypeByName());
// Add requirements for associated types.
for (const auto &nested : nestedTypes) {
auto rep = nested.second->getRepresentative();
if (knownPAs.insert(rep)) {
// Form the dependent type that refers to this archetype.
auto assocType = pa->getAssociatedType(tu, nested.first);
if (!assocType)
continue; // FIXME: If we do this late enough, there will be no failure.
auto nestedType = DependentMemberType::get(type, assocType,
tu.getASTContext());
addRequirements(tu, nestedType, rep, knownPAs, requirements);
}
}
}
/// Collect the set of requirements placed on the given generic parameters and
/// their associated types.
static void collectRequirements(ArchetypeBuilder &builder,
ArrayRef<GenericTypeParamType *> params,
SmallVectorImpl<Requirement> &requirements) {
// Find the "primary" potential archetypes, from which we'll collect all
// of the requirements.
llvm::SmallPtrSet<ArchetypeBuilder::PotentialArchetype *, 16> knownPAs;
llvm::SmallVector<GenericTypeParamType *, 8> primary;
for (auto param : params) {
auto pa = builder.resolveType(param);
assert(pa && "Missing potential archetype for generic parameter");
// We only care about the representative.
pa = pa->getRepresentative();
// If the potential archetype has a parent, it isn't primary.
if (pa->getRepresentative()->getParent())
continue;
if (knownPAs.insert(pa))
primary.push_back(param);
}
// For each of the primary potential archetypes, add the requirements,
// along with the requirements of its nested types.
for (auto param : primary) {
auto pa = builder.resolveType(param)->getRepresentative();
addRequirements(builder.getTranslationUnit(), param, pa, knownPAs,
requirements);
}
}
/// Check the signature of a generic function.
static bool checkGenericFuncSignature(TypeChecker &tc,
ArchetypeBuilder *builder,
FuncDecl *func,
GenericTypeResolver &resolver) {
bool badType = false;
// Check the generic parameter list.
checkGenericParameters(tc, builder, func->getGenericParams(), resolver);
// Check the parameter patterns.
for (auto pattern : func->getArgParamPatterns()) {
// Check the pattern.
if (tc.typeCheckPattern(pattern, func, /*allowUnboundGenerics=*/false,
&resolver))
badType = true;
// Infer requirements from the pattern.
if (builder) {
builder->inferRequirements(pattern);
}
}
// If there is a declared result type, check that as well.
if (!func->getBodyResultTypeLoc().isNull()) {
// Check the result type of the function.
if (tc.validateType(func->getBodyResultTypeLoc(),
/*allowUnboundGenerics=*/false,
&resolver)) {
badType = true;
}
// Infer requirements from it.
if (builder) {
builder->inferRequirements(func->getBodyResultTypeLoc().getTypeRepr());
}
}
return badType;
}
bool TypeChecker::validateGenericFuncSignature(FuncDecl *func) {
// Create the archetype builder.
ArchetypeBuilder builder = createArchetypeBuilder(*this);
// Type check the function declaration, treating all generic type
// parameters as dependent, unresolved.
PartialGenericTypeToArchetypeResolver partialResolver(*this);
if (checkGenericFuncSignature(*this, &builder, func, partialResolver)) {
func->setType(ErrorType::get(Context));
return true;
}
// The archetype builder now has all of the requirements, although there might
// still be errors that have not yet been diagnosed. Revert the generic
// function signature and type-check it again, completely.
revertGenericFuncSignature(func);
CompleteGenericTypeResolver completeResolver(*this, builder);
if (checkGenericFuncSignature(*this, nullptr, func, completeResolver)) {
func->setType(ErrorType::get(Context));
return true;
}
// The generic function signature is complete and well-formed. Determine
// the type of the generic function.
// Collect the complete set of generic parameter types.
SmallVector<GenericTypeParamType *, 4> allGenericParams;
collectGenericParamTypes(func->getGenericParams(), allGenericParams);
// Collect the requirements placed on the generic parameter types.
SmallVector<Requirement, 4> requirements;
collectRequirements(builder, allGenericParams, requirements);
// Compute the function type.
auto funcTy = func->getBodyResultTypeLoc().getType();
if (!funcTy) {
funcTy = TupleType::getEmpty(Context);
}
auto patterns = func->getArgParamPatterns();
for (unsigned i = 0, e = patterns.size(); i != e; ++i) {
Type argTy = patterns[e - i - 1]->getType();
// Validate and consume the function type attributes.
// FIXME: Hacked up form of validateAndConsumeFunctionTypeAttributes().
auto info = AnyFunctionType::ExtInfo()
.withIsNoReturn(func->getAttrs().isNoReturn());
if (i == e-1) {
funcTy = GenericFunctionType::get(allGenericParams, requirements,
argTy, funcTy, info, Context);
} else {
funcTy = FunctionType::get(argTy, funcTy, info, Context);
}
}
return false;
}
SpecializeExpr * SpecializeExpr *
TypeChecker::buildSpecializeExpr(Expr *Sub, Type Ty, TypeChecker::buildSpecializeExpr(Expr *Sub, Type Ty,
const TypeSubstitutionMap &Substitutions, const TypeSubstitutionMap &Substitutions,

View File

@@ -29,6 +29,7 @@
namespace swift { namespace swift {
class ArchetypeBuilder;
class GenericTypeResolver; class GenericTypeResolver;
class TypeChecker; class TypeChecker;
@@ -325,6 +326,22 @@ public:
validateDecl(VD, true); validateDecl(VD, true);
} }
/// Validate the signature of a generic function.
///
/// \param func The generic function.
///
/// \returns true if an error occurred, or false otherwise.
bool validateGenericFuncSignature(FuncDecl *func);
/// Revert the signature of a generic function to its pre-type-checked state,
/// so that it can be type checked again when we have resolved its generic
/// parameters.
void revertGenericFuncSignature(FuncDecl *func);
/// Check the inheritance clause of the given declaration.
void checkInheritanceClause(Decl *decl,
GenericTypeResolver *resolver = nullptr);
/// Retrieve the set of protocols to which this nominal type declaration /// Retrieve the set of protocols to which this nominal type declaration
/// directly conforms, i.e., as specified in its own inheritance clause. /// directly conforms, i.e., as specified in its own inheritance clause.
/// ///

View File

@@ -455,7 +455,7 @@ GenericParamList *ModuleFile::maybeReadGenericParams(DeclContext *DC) {
archetypes.push_back(getType(next)->castTo<ArchetypeType>()); archetypes.push_back(getType(next)->castTo<ArchetypeType>());
SmallVector<GenericParam, 8> params; SmallVector<GenericParam, 8> params;
SmallVector<Requirement, 8> requirements; SmallVector<RequirementRepr, 8> requirements;
while (true) { while (true) {
lastRecordOffset.reset(); lastRecordOffset.reset();
bool shouldContinue = true; bool shouldContinue = true;
@@ -486,7 +486,7 @@ GenericParamList *ModuleFile::maybeReadGenericParams(DeclContext *DC) {
auto subject = TypeLoc::withoutLoc(getType(rawTypeIDs[0])); auto subject = TypeLoc::withoutLoc(getType(rawTypeIDs[0]));
auto constraint = TypeLoc::withoutLoc(getType(rawTypeIDs[1])); auto constraint = TypeLoc::withoutLoc(getType(rawTypeIDs[1]));
requirements.push_back(Requirement::getConformance(subject, requirements.push_back(RequirementRepr::getConformance(subject,
SourceLoc(), SourceLoc(),
constraint)); constraint));
break; break;
@@ -496,7 +496,7 @@ GenericParamList *ModuleFile::maybeReadGenericParams(DeclContext *DC) {
auto first = TypeLoc::withoutLoc(getType(rawTypeIDs[0])); auto first = TypeLoc::withoutLoc(getType(rawTypeIDs[0]));
auto second = TypeLoc::withoutLoc(getType(rawTypeIDs[1])); auto second = TypeLoc::withoutLoc(getType(rawTypeIDs[1]));
requirements.push_back(Requirement::getSameType(first, requirements.push_back(RequirementRepr::getSameType(first,
SourceLoc(), SourceLoc(),
second)); second));
break; break;

View File

@@ -1493,6 +1493,10 @@ void Serializer::writeType(Type ty) {
break; break;
} }
case TypeKind::GenericFunction: {
llvm_unreachable("Cannot serialize generic function types yet");
}
case TypeKind::GenericTypeParam: { case TypeKind::GenericTypeParam: {
auto genericParam = cast<GenericTypeParamType>(ty.getPointer()); auto genericParam = cast<GenericTypeParamType>(ty.getPointer());
unsigned abbrCode = DeclTypeAbbrCodes[GenericTypeParamTypeLayout::Code]; unsigned abbrCode = DeclTypeAbbrCodes[GenericTypeParamTypeLayout::Code];