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 Pattern;
class ProtocolDecl;
class Requirement;
class RequirementRepr;
class SourceLoc;
class TranslationUnit;
class Type;
@@ -104,6 +104,9 @@ public:
ArchetypeBuilder(ArchetypeBuilder &&);
~ArchetypeBuilder();
/// Retrieve the translation unit.
TranslationUnit &getTranslationUnit() const { return TU; }
/// \brief Add a new generic parameter for which there may be requirements.
///
/// \returns true if an error occurred, false otherwise.
@@ -114,7 +117,7 @@ public:
///
/// \returns true if this requirement makes the set of requirements
/// 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
/// parameters.
@@ -180,7 +183,6 @@ public:
/// list.
ArrayRef<ArchetypeType *> getAllArchetypes();
// FIXME: Infer requirements from signatures
// FIXME: Compute the set of 'extra' witness tables needed to express this
// requirement set.
@@ -233,6 +235,10 @@ public:
/// \brief Retrieve the full display name of this potential archetype.
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.
ArrayRef<ProtocolDecl *> getConformsTo() const {
return llvm::makeArrayRef(ConformsTo.begin(), ConformsTo.end());
@@ -241,6 +247,11 @@ public:
/// Retrieve the superclass of this archetype.
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.,
/// the number of associated type references.
unsigned getNestingDepth() const;
@@ -257,6 +268,9 @@ public:
ArchetypeType *getArchetype(AssociatedTypeDecl * /*nullable*/ rootAssocTy,
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);
friend class ArchetypeBuilder;

View File

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

View File

@@ -20,6 +20,7 @@
#include "swift/AST/DeclContext.h"
#include "swift/AST/DefaultArgumentKind.h"
#include "swift/AST/Ownership.h"
#include "swift/AST/Requirement.h"
#include "swift/AST/Type.h"
#include "swift/AST/Identifier.h"
#include "swift/Basic/ArrayRefView.h"
@@ -40,6 +41,7 @@ namespace swift {
class ClassDecl;
class ExprHandle;
class GenericTypeParamDecl;
class GenericTypeParamType;
class GenericParam;
class GenericParamList;
class Identifier;
@@ -361,12 +363,12 @@ private:
// Make vanilla new/delete illegal for Types.
void *operator new(size_t Bytes) throw() = delete;
void operator delete(void *Data) throw() = delete;
void *operator new(size_t Bytes, void *Mem) throw() = delete;
public:
// Only allow allocation of Types using the allocator in ASTContext
// or by doing a placement new.
void *operator new(size_t bytes, const ASTContext &ctx,
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
@@ -1394,7 +1396,83 @@ private:
const ASTContext &C);
};
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
/// constant size. For example "int[]" and "int[4]". Array types cannot have
/// size = 0.
@@ -2274,6 +2352,19 @@ case TypeKind::Id:
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:
return cast<ArrayType>(base)->getBaseType().findIf(pred);
@@ -2535,6 +2626,72 @@ case TypeKind::Id:
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: {
auto array = cast<ArrayType>(base);
auto baseTy = array->getBaseType().transform(ctx, fn);

View File

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

View File

@@ -126,6 +126,7 @@ struct ASTContext::Implementation {
};
llvm::DenseMap<Module*, ModuleType*> ModuleTypes;
llvm::FoldingSet<GenericFunctionType> GenericFunctionTypes;
llvm::DenseMap<unsigned, BuiltinIntegerType*> IntegerTypes;
llvm::FoldingSet<ProtocolCompositionType> ProtocolCompositionTypes;
llvm::FoldingSet<BuiltinVectorType> BuiltinVectorTypes;
@@ -1186,6 +1187,96 @@ PolymorphicFunctionType::PolymorphicFunctionType(Type input, Type output,
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
/// specified size.
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::Function:
case TypeKind::PolymorphicFunction:
case TypeKind::GenericFunction:
OS << '(';
visit(T);
OS << ')';
@@ -1317,6 +1318,58 @@ public:
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) {
printWithParensIfNotSimple(T->getBaseType());
OS << '[' << T->getSize() << ']';

View File

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

View File

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

View File

@@ -130,6 +130,7 @@ bool CanType::hasReferenceSemanticsImpl(CanType type) {
case TypeKind::BoundGenericClass:
case TypeKind::Function:
case TypeKind::PolymorphicFunction:
case TypeKind::GenericFunction:
return true;
case TypeKind::UnboundGeneric:
@@ -220,6 +221,9 @@ bool TypeBase::isUnspecializedGeneric() {
funcTy->getResult()->isUnspecializedGeneric();
}
case TypeKind::GenericFunction:
return true;
case TypeKind::Class:
case TypeKind::Struct:
case TypeKind::Enum:
@@ -623,6 +627,34 @@ CanType TypeBase::getCanonicalType() {
In->getASTContext());
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: {
FunctionType *FT = cast<FunctionType>(this);
Type In = FT->getInput()->getCanonicalType();
@@ -693,6 +725,7 @@ TypeBase *TypeBase::getDesugaredType() {
case TypeKind::Tuple:
case TypeKind::Function:
case TypeKind::PolymorphicFunction:
case TypeKind::GenericFunction:
case TypeKind::Array:
case TypeKind::LValue:
case TypeKind::ProtocolComposition:
@@ -849,7 +882,8 @@ bool TypeBase::isSpelledLike(Type other) {
return true;
}
case TypeKind::PolymorphicFunction: {
case TypeKind::PolymorphicFunction:
case TypeKind::GenericFunction: {
// Polymorphic function types should never be explicitly spelled.
return false;
}

View File

@@ -429,6 +429,12 @@ namespace {
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) {
if (auto metatype = tryGetLocal(type))
return metatype;

View File

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

View File

@@ -108,6 +108,7 @@ public:
->visitArchetypeType(cast<ArchetypeType>(origTy),
substTy);
case TypeKind::GenericFunction:
case TypeKind::GenericTypeParam:
case TypeKind::DependentMember:
// 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.
SourceLoc WhereLoc;
SmallVector<Requirement, 4> Requirements;
SmallVector<RequirementRepr, 4> Requirements;
if (Tok.is(tok::kw_where) &&
parseGenericWhereClause(WhereLoc, Requirements)) {
Invalid = true;
@@ -146,8 +146,8 @@ GenericParamList *Parser::maybeParseGenericParams() {
/// same-type-requirement:
/// type-identifier '==' type-identifier
bool Parser::parseGenericWhereClause(SourceLoc &WhereLoc,
SmallVectorImpl<Requirement> &Requirements) {
// Parse the 'requires'.
SmallVectorImpl<RequirementRepr> &Requirements) {
// Parse the 'where'.
WhereLoc = consumeToken(tok::kw_where);
bool Invalid = false;
do {
@@ -176,7 +176,7 @@ bool Parser::parseGenericWhereClause(SourceLoc &WhereLoc,
}
// Add the requirement.
Requirements.push_back(Requirement::getConformance(FirstType.get(),
Requirements.push_back(RequirementRepr::getConformance(FirstType.get(),
ColonLoc,
Protocol.get()));
} else if ((Tok.isAnyOperator() && Tok.getText() == "==") ||
@@ -196,7 +196,7 @@ bool Parser::parseGenericWhereClause(SourceLoc &WhereLoc,
}
// Add the requirement
Requirements.push_back(Requirement::getSameType(FirstType.get(),
Requirements.push_back(RequirementRepr::getSameType(FirstType.get(),
EqualLoc,
SecondType.get()));
} else {

View File

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

View File

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

View File

@@ -1715,6 +1715,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, TypeMatchKind kind,
}
case TypeKind::PolymorphicFunction:
case TypeKind::GenericFunction:
llvm_unreachable("Polymorphic function type should have been opened");
case TypeKind::Array: {
@@ -2239,6 +2240,7 @@ ConstraintSystem::simplifyConstructionConstraint(Type valueType, Type argType,
case TypeKind::Error:
return SolutionKind::Error;
case TypeKind::GenericFunction:
case TypeKind::GenericTypeParam:
case TypeKind::DependentMember:
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,
/// recording the superclass (if any and if allowed) as well as the protocols
/// 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;
// 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;
llvm::SmallSetVector<ProtocolDecl *, 4> allProtocols;
llvm::SmallDenseMap<CanType, SourceRange> inheritedTypes;
addImplicitConformances(tc, decl, allProtocols);
addImplicitConformances(*this, decl, allProtocols);
for (unsigned i = 0, n = inheritedClause.size(); i != n; ++i) {
auto &inherited = inheritedClause[i];
// Validate the type.
if (tc.validateType(inherited)) {
inherited.setInvalidType(tc.Context);
if (validateType(inherited, /*allowUnboundGenerics=*/false, resolver)) {
inherited.setInvalidType(Context);
continue;
}
@@ -242,14 +248,14 @@ static void checkInheritanceClause(TypeChecker &tc, Decl *decl) {
auto knownType = inheritedTypes.find(inheritedCanTy);
if (knownType != inheritedTypes.end()) {
SourceLoc afterPriorLoc
= Lexer::getLocForEndOfToken(tc.Context.SourceMgr,
= Lexer::getLocForEndOfToken(Context.SourceMgr,
inheritedClause[i-1].getSourceRange().End);
SourceLoc afterMyEndLoc
= Lexer::getLocForEndOfToken(tc.Context.SourceMgr,
= Lexer::getLocForEndOfToken(Context.SourceMgr,
inherited.getSourceRange().End);
tc.diagnose(inherited.getSourceRange().Start,
diag::duplicate_inheritance, inheritedTy)
diagnose(inherited.getSourceRange().Start,
diag::duplicate_inheritance, inheritedTy)
.fixItRemoveChars(afterPriorLoc, afterMyEndLoc)
.highlight(knownType->second);
continue;
@@ -263,8 +269,8 @@ static void checkInheritanceClause(TypeChecker &tc, Decl *decl) {
if (auto protoTy = inheritedTy->getAs<ProtocolType>()) {
if (protoTy->getDecl()->isSpecificProtocol(
KnownProtocolKind::DynamicLookup)) {
tc.diagnose(inheritedClause[i].getSourceRange().Start,
diag::dynamic_lookup_conformance);
diagnose(inheritedClause[i].getSourceRange().Start,
diag::dynamic_lookup_conformance);
continue;
}
}
@@ -279,8 +285,8 @@ static void checkInheritanceClause(TypeChecker &tc, Decl *decl) {
if (isa<EnumDecl>(decl)) {
// Check if we already had a raw type.
if (superclassTy) {
tc.diagnose(inherited.getSourceRange().Start,
diag::multiple_enum_raw_types, superclassTy, inheritedTy)
diagnose(inherited.getSourceRange().Start,
diag::multiple_enum_raw_types, superclassTy, inheritedTy)
.highlight(superclassRange);
continue;
}
@@ -289,14 +295,14 @@ static void checkInheritanceClause(TypeChecker &tc, Decl *decl) {
if (i > 0) {
SourceLoc afterPriorLoc
= Lexer::getLocForEndOfToken(
tc.Context.SourceMgr,
Context.SourceMgr,
inheritedClause[i-1].getSourceRange().End);
SourceLoc afterMyEndLoc
= Lexer::getLocForEndOfToken(tc.Context.SourceMgr,
= Lexer::getLocForEndOfToken(Context.SourceMgr,
inherited.getSourceRange().End);
tc.diagnose(inherited.getSourceRange().Start,
diag::raw_type_not_first, inheritedTy)
diagnose(inherited.getSourceRange().Start,
diag::raw_type_not_first, inheritedTy)
.fixItRemoveChars(afterPriorLoc, afterMyEndLoc)
.fixItInsert(inheritedClause[0].getSourceRange().Start,
inheritedTy.getString() + ", ");
@@ -318,8 +324,8 @@ static void checkInheritanceClause(TypeChecker &tc, Decl *decl) {
// Complain about multiple inheritance.
// Don't emit a Fix-It here. The user has to think harder about this.
tc.diagnose(inherited.getSourceRange().Start,
diag::multiple_inheritance, superclassTy, inheritedTy)
diagnose(inherited.getSourceRange().Start,
diag::multiple_inheritance, superclassTy, inheritedTy)
.highlight(superclassRange);
continue;
}
@@ -330,11 +336,11 @@ static void checkInheritanceClause(TypeChecker &tc, Decl *decl) {
// FIXME: Allow type aliases to 'inherit' from classes, as an additional
// kind of requirement?
if (!canInheritClass(decl)) {
tc.diagnose(decl->getLoc(),
isa<ExtensionDecl>(decl)
? diag::extension_class_inheritance
: diag::non_class_inheritance,
getDeclaredType(decl), inheritedTy)
diagnose(decl->getLoc(),
isa<ExtensionDecl>(decl)
? diag::extension_class_inheritance
: diag::non_class_inheritance,
getDeclaredType(decl), inheritedTy)
.highlight(inherited.getSourceRange());
continue;
}
@@ -343,14 +349,14 @@ static void checkInheritanceClause(TypeChecker &tc, Decl *decl) {
if (i > 0) {
SourceLoc afterPriorLoc
= Lexer::getLocForEndOfToken(
tc.Context.SourceMgr,
Context.SourceMgr,
inheritedClause[i-1].getSourceRange().End);
SourceLoc afterMyEndLoc
= Lexer::getLocForEndOfToken(tc.Context.SourceMgr,
= Lexer::getLocForEndOfToken(Context.SourceMgr,
inherited.getSourceRange().End);
tc.diagnose(inherited.getSourceRange().Start,
diag::superclass_not_first, inheritedTy)
diagnose(inherited.getSourceRange().Start,
diag::superclass_not_first, inheritedTy)
.fixItRemoveChars(afterPriorLoc, afterMyEndLoc)
.fixItInsert(inheritedClause[0].getSourceRange().Start,
inheritedTy.getString() + ", ");
@@ -369,11 +375,11 @@ static void checkInheritanceClause(TypeChecker &tc, Decl *decl) {
continue;
// We can't inherit from a non-class, non-protocol type.
tc.diagnose(decl->getLoc(),
canInheritClass(decl)
? diag::inheritance_from_non_protocol_or_class
: diag::inheritance_from_non_protocol,
inheritedTy);
diagnose(decl->getLoc(),
canInheritClass(decl)
? diag::inheritance_from_non_protocol_or_class
: diag::inheritance_from_non_protocol,
inheritedTy);
// FIXME: Note pointing to the declaration 'inheritedTy' references?
}
@@ -382,7 +388,7 @@ static void checkInheritanceClause(TypeChecker &tc, Decl *decl) {
if (allProtocols.empty() && !superclassTy)
return;
auto allProtocolsCopy = tc.Context.AllocateCopy(allProtocols);
auto allProtocolsCopy = Context.AllocateCopy(allProtocols);
if (auto ext = dyn_cast<ExtensionDecl>(decl)) {
assert(!superclassTy && "Extensions can't add superclasses");
ext->setProtocols(allProtocolsCopy);
@@ -407,7 +413,7 @@ static void checkInheritanceClause(TypeChecker &tc, Decl *decl) {
unsigned conformancesSize
= sizeof(ProtocolConformance *) * allProtocols.size();
ProtocolConformance **conformances
= (ProtocolConformance **)tc.Context.Allocate(
= (ProtocolConformance **)Context.Allocate(
conformancesSize,
alignof(ProtocolConformance *));
memset(conformances, 0, conformancesSize);
@@ -427,7 +433,7 @@ static ArrayRef<ProtocolDecl *> getInheritedForCycleCheck(TypeChecker &tc,
static ArrayRef<ClassDecl *> getInheritedForCycleCheck(TypeChecker &tc,
ClassDecl *classDecl,
ClassDecl **scratch) {
checkInheritanceClause(tc, classDecl);
tc.checkInheritanceClause(classDecl);
if (classDecl->hasSuperclass()) {
*scratch = classDecl->getSuperclass()->getClassOrBoundGenericClass();
@@ -440,7 +446,7 @@ static ArrayRef<ClassDecl *> getInheritedForCycleCheck(TypeChecker &tc,
static ArrayRef<EnumDecl *> getInheritedForCycleCheck(TypeChecker &tc,
EnumDecl *enumDecl,
EnumDecl **scratch) {
checkInheritanceClause(tc, enumDecl);
tc.checkInheritanceClause(enumDecl);
if (enumDecl->hasRawType()) {
*scratch = enumDecl->getRawType()->getEnumOrBoundGenericEnum();
@@ -585,7 +591,8 @@ static CanType getExtendedType(ExtensionDecl *ED) {
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) {
return ArchetypeBuilder(
TC.TU, TC.Diags,
@@ -593,13 +600,11 @@ static ArchetypeBuilder createArchetypeBuilder(TypeChecker &TC) {
return TC.getDirectConformsTo(protocol);
},
[&](AbstractTypeParamDecl *assocType) -> ArrayRef<ProtocolDecl *> {
checkInheritanceClause(TC, assocType);
TC.checkInheritanceClause(assocType);
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) {
// Make sure we validate the type again.
tl.setType(Type(), /*validated=*/false);
@@ -663,9 +668,7 @@ static void revertDependentTypeLoc(TypeLoc &tl, DeclContext *dc) {
tl.getTypeRepr()->walk(RevertWalker(dc));
}
/// Revert the dependently-typed TypeLocs within the given pattern to a
/// state where generic parameters have not yet been resolved.
void revertDependentPattern(Pattern *pattern, DeclContext *dc) {
static void revertDependentPattern(Pattern *pattern, DeclContext *dc) {
// Clear out the pattern's type.
if (pattern->hasType())
pattern->overwriteType(Type());
@@ -718,9 +721,9 @@ void revertDependentPattern(Pattern *pattern, DeclContext *dc) {
/// Check the given generic parameter list, introduce the generic parameters
/// and requirements into the archetype builder, but don't assign archetypes
/// yet.
void checkGenericParamList(ArchetypeBuilder &builder,
GenericParamList *genericParams,
TypeChecker &TC) {
static void checkGenericParamList(ArchetypeBuilder &builder,
GenericParamList *genericParams,
TypeChecker &TC) {
assert(genericParams && "Missing generic parameters");
unsigned Depth = genericParams->getDepth();
@@ -733,7 +736,7 @@ void checkGenericParamList(ArchetypeBuilder &builder,
TypeParam->setDepth(Depth);
// Check the constraints on the type parameter.
checkInheritanceClause(TC, TypeParam);
TC.checkInheritanceClause(TypeParam);
// Add the generic parameter to the builder.
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
/// the generic parameters.
void finalizeGenericParamList(ArchetypeBuilder &builder,
GenericParamList *genericParams,
DeclContext *dc,
TypeChecker &TC) {
static void finalizeGenericParamList(ArchetypeBuilder &builder,
GenericParamList *genericParams,
DeclContext *dc,
TypeChecker &TC) {
// Wire up the archetypes.
builder.assignArchetypes();
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 {
@@ -1077,7 +1142,7 @@ public:
}
if (!isa<ProtocolDecl>(TAD->getDeclContext()))
checkInheritanceClause(TC, TAD);
TC.checkInheritanceClause(TAD);
}
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()) {
gp->setOuterParameters(outerGenericParams);
builder.emplace(createArchetypeBuilder(TC));
checkGenericParamList(*builder, gp, TC);
}
// If we have generic parameters, create archetypes now.
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>()) {
if (TC.validateGenericFuncSignature(FD))
isInvalid = true;
} else {
// Assign archetypes... after reverting the signature once again.
revertSignature();
finalizeGenericParamList(*builder, FD->getGenericParams(), FD, TC);
else {
// Create a fresh archetype builder.
ArchetypeBuilder builder = createArchetypeBuilder(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();
}
checkInheritanceClause(TC, ED);
TC.checkInheritanceClause(ED);
if (auto nominal = ExtendedTy->getAnyNominal())
TC.validateDecl(nominal);
@@ -1973,7 +2002,7 @@ void TypeChecker::validateDecl(ValueDecl *D, bool resolveTypeParams) {
case DeclKind::Class: {
auto nominal = cast<NominalTypeDecl>(D);
for (auto ext : nominal->getExtensions())
checkInheritanceClause(*this, ext);
checkInheritanceClause(ext);
if (nominal->hasType())
return;
@@ -1992,7 +2021,7 @@ void TypeChecker::validateDecl(ValueDecl *D, bool resolveTypeParams) {
nominal->computeType();
validateAttributes(*this, D);
checkInheritanceClause(*this, D);
checkInheritanceClause(D);
// Mark a class as [objc]. This must happen before checking its members.
if (auto CD = dyn_cast<ClassDecl>(nominal)) {
@@ -2019,14 +2048,14 @@ void TypeChecker::validateDecl(ValueDecl *D, bool resolveTypeParams) {
return;
proto->computeType();
checkInheritanceClause(*this, D);
checkInheritanceClause(D);
validateAttributes(*this, D);
// Fix the 'Self' associated type.
AssociatedTypeDecl *selfDecl = nullptr;
for (auto member : proto->getMembers()) {
if (auto AssocType = dyn_cast<AssociatedTypeDecl>(member)) {
checkInheritanceClause(*this, AssocType);
checkInheritanceClause(AssocType);
if (AssocType->isSelf()) {
selfDecl = AssocType;
@@ -2119,13 +2148,13 @@ void TypeChecker::validateDecl(ValueDecl *D, bool resolveTypeParams) {
ArrayRef<ProtocolDecl *>
TypeChecker::getDirectConformsTo(NominalTypeDecl *nominal) {
checkInheritanceClause(*this, nominal);
checkInheritanceClause(nominal);
return nominal->getProtocols();
}
ArrayRef<ProtocolDecl *>
TypeChecker::getDirectConformsTo(ExtensionDecl *ext) {
checkInheritanceClause(*this, ext);
checkInheritanceClause(ext);
return ext->getProtocols();
}
@@ -2388,6 +2417,7 @@ bool TypeChecker::isDefaultInitializable(Type ty, Expr **initializer,
return true;
}
case TypeKind::GenericFunction:
case TypeKind::GenericTypeParam:
case TypeKind::DependentMember:
llvm_unreachable("Should never ask about dependent types");

View File

@@ -130,6 +130,356 @@ Type CompleteGenericTypeResolver::resolveDependentMemberType(
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 *
TypeChecker::buildSpecializeExpr(Expr *Sub, Type Ty,
const TypeSubstitutionMap &Substitutions,

View File

@@ -29,6 +29,7 @@
namespace swift {
class ArchetypeBuilder;
class GenericTypeResolver;
class TypeChecker;
@@ -325,6 +326,22 @@ public:
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
/// 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>());
SmallVector<GenericParam, 8> params;
SmallVector<Requirement, 8> requirements;
SmallVector<RequirementRepr, 8> requirements;
while (true) {
lastRecordOffset.reset();
bool shouldContinue = true;
@@ -486,7 +486,7 @@ GenericParamList *ModuleFile::maybeReadGenericParams(DeclContext *DC) {
auto subject = TypeLoc::withoutLoc(getType(rawTypeIDs[0]));
auto constraint = TypeLoc::withoutLoc(getType(rawTypeIDs[1]));
requirements.push_back(Requirement::getConformance(subject,
requirements.push_back(RequirementRepr::getConformance(subject,
SourceLoc(),
constraint));
break;
@@ -496,7 +496,7 @@ GenericParamList *ModuleFile::maybeReadGenericParams(DeclContext *DC) {
auto first = TypeLoc::withoutLoc(getType(rawTypeIDs[0]));
auto second = TypeLoc::withoutLoc(getType(rawTypeIDs[1]));
requirements.push_back(Requirement::getSameType(first,
requirements.push_back(RequirementRepr::getSameType(first,
SourceLoc(),
second));
break;

View File

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