Parameterize the resolution of generic type parameter types to archetypes.

When type checking, allow the caller to customize the resolution of generic
type parameter types based on the context, for example, by choosing to
substitute in an archetype (or not) and allowing one to resolve a dependent
member reference via a specific archetype.

No actual functionality change here.


Swift SVN r8797
This commit is contained in:
Doug Gregor
2013-09-30 23:24:53 +00:00
parent c003b4e23d
commit f5d4269f53
12 changed files with 376 additions and 98 deletions

View File

@@ -2003,22 +2003,36 @@ public:
/// generic parameter. /// generic parameter.
class DependentMemberType : public TypeBase { class DependentMemberType : public TypeBase {
Type Base; Type Base;
Identifier Name; llvm::PointerUnion<Identifier, AssociatedTypeDecl *> NameOrAssocType;
DependentMemberType(Type base, Identifier name, const ASTContext *ctx, DependentMemberType(Type base, Identifier name, const ASTContext *ctx,
bool hasTypeVariable) bool hasTypeVariable)
: TypeBase(TypeKind::DependentMember, ctx, hasTypeVariable), : TypeBase(TypeKind::DependentMember, ctx, hasTypeVariable),
Base(base), Name(name) { } Base(base), NameOrAssocType(name) { }
DependentMemberType(Type base, AssociatedTypeDecl *assocType,
const ASTContext *ctx, bool hasTypeVariable)
: TypeBase(TypeKind::DependentMember, ctx, hasTypeVariable),
Base(base), NameOrAssocType(assocType) { }
public: public:
static DependentMemberType *get(Type base, Identifier name, static DependentMemberType *get(Type base, Identifier name,
const ASTContext &ctx); const ASTContext &ctx);
static DependentMemberType *get(Type base, AssociatedTypeDecl *assocType,
const ASTContext &ctx);
/// Retrieve the base type. /// Retrieve the base type.
Type getBase() const { return Base; } Type getBase() const { return Base; }
/// Retrieve the name of the member type. /// Retrieve the name of the member type.
Identifier getName() const { return Name; } Identifier getName() const;
/// Retrieve the associated type referenced as a member.
///
/// The associated type will only be available after successful type checking.
AssociatedTypeDecl *getAssocType() const {
return NameOrAssocType.dyn_cast<AssociatedTypeDecl *>();
}
// Implement isa/cast/dyncast/etc. // Implement isa/cast/dyncast/etc.
static bool classof(const TypeBase *T) { static bool classof(const TypeBase *T) {

View File

@@ -116,7 +116,7 @@ struct ASTContext::Implementation {
llvm::DenseMap<std::pair<Type, LValueType::Qual::opaque_type>, LValueType*> llvm::DenseMap<std::pair<Type, LValueType::Qual::opaque_type>, LValueType*>
LValueTypes; LValueTypes;
llvm::DenseMap<std::pair<Type, Type>, SubstitutedType *> SubstitutedTypes; llvm::DenseMap<std::pair<Type, Type>, SubstitutedType *> SubstitutedTypes;
llvm::DenseMap<std::pair<Type, Identifier>, DependentMemberType *> llvm::DenseMap<std::pair<Type, void*>, DependentMemberType *>
DependentMemberTypes; DependentMemberTypes;
llvm::FoldingSet<EnumType> EnumTypes; llvm::FoldingSet<EnumType> EnumTypes;
llvm::FoldingSet<StructType> StructTypes; llvm::FoldingSet<StructType> StructTypes;
@@ -1269,7 +1269,9 @@ DependentMemberType *DependentMemberType::get(Type base, Identifier name,
bool hasTypeVariable = base->hasTypeVariable(); bool hasTypeVariable = base->hasTypeVariable();
auto arena = getArena(hasTypeVariable); auto arena = getArena(hasTypeVariable);
auto *&known = ctx.Impl.getArena(arena).DependentMemberTypes[{base, name}]; llvm::PointerUnion<Identifier, AssociatedTypeDecl *> stored(name);
auto *&known = ctx.Impl.getArena(arena).DependentMemberTypes[
{base, stored.getOpaqueValue()}];
if (!known) { if (!known) {
const ASTContext *canonicalCtx = base->isCanonical() ? &ctx : nullptr; const ASTContext *canonicalCtx = base->isCanonical() ? &ctx : nullptr;
known = new (ctx, arena) DependentMemberType(base, name, canonicalCtx, known = new (ctx, arena) DependentMemberType(base, name, canonicalCtx,
@@ -1278,6 +1280,23 @@ DependentMemberType *DependentMemberType::get(Type base, Identifier name,
return known; return known;
} }
DependentMemberType *DependentMemberType::get(Type base,
AssociatedTypeDecl *assocType,
const ASTContext &ctx) {
bool hasTypeVariable = base->hasTypeVariable();
auto arena = getArena(hasTypeVariable);
llvm::PointerUnion<Identifier, AssociatedTypeDecl *> stored(assocType);
auto *&known = ctx.Impl.getArena(arena).DependentMemberTypes[
{base, stored.getOpaqueValue()}];
if (!known) {
const ASTContext *canonicalCtx = base->isCanonical() ? &ctx : nullptr;
known = new (ctx, arena) DependentMemberType(base, assocType, canonicalCtx,
hasTypeVariable);
}
return known;
}
void *ExprHandle::operator new(size_t Bytes, ASTContext &C, void *ExprHandle::operator new(size_t Bytes, ASTContext &C,
unsigned Alignment) { unsigned Alignment) {
return C.Allocate(Bytes, Alignment); return C.Allocate(Bytes, Alignment);

View File

@@ -1405,4 +1405,10 @@ Type TypeBase::getTypeOfMember(Module *module, ValueDecl *member,
resolver); resolver);
} }
Identifier DependentMemberType::getName() const {
if (NameOrAssocType.is<Identifier>())
return NameOrAssocType.get<Identifier>();
return NameOrAssocType.get<AssociatedTypeDecl *>()->getName();
}

View File

@@ -0,0 +1,95 @@
//===-- GenericTypeResolver.h - Generic Type Resolver Interface -*- 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 GenericTypeResolver abstract interface.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SEMA_GENERICTYPERESOLVER_H
#define SWIFT_SEMA_GENERICTYPERESOLVER_H
#include "swift/AST/Type.h"
#include "swift/Basic/SourceLoc.h"
namespace swift {
class AssociatedTypeDecl;
class Identifier;
/// Abstract class that resolves references into generic types during
/// type resolution.
class GenericTypeResolver {
public:
virtual ~GenericTypeResolver();
/// Resolve the given generic type parameter to its type.
///
/// This routine is used whenever type checking encounters a reference to a
/// generic parameter. It can replace the generic parameter with (for example)
/// a concrete type or an archetype, depending on context.
///
/// \param gp The generic parameter to resolve.
///
/// \returns The resolved generic type parameter type, which may be \c gp.
virtual Type resolveGenericTypeParamType(GenericTypeParamType *gp) = 0;
/// Resolve a reference to a member within a dependent type to an associated
/// type.
///
/// \param baseTy The base of the member access.
/// \param baseRange The source range covering the base type.
/// \param name The name of the member type.
/// \param nameLoc The location of the member name.
///
/// \returns The associated type to which the member refers, or null if
/// no such associated type exists.
virtual AssociatedTypeDecl *resolveDependentMemberType(Type baseTy,
SourceRange baseRange,
Identifier name,
SourceLoc nameLoc) = 0;
};
/// Generic type resolver that maps a generic type parameter type to its
/// archetype.
///
/// This generic type resolver replaces generic type parameter types with their
/// corresponding archetypes, eliminating all dependent types in the process.
class GenericTypeToArchetypeResolver : public GenericTypeResolver {
virtual Type resolveGenericTypeParamType(GenericTypeParamType *gp);
virtual AssociatedTypeDecl *resolveDependentMemberType(Type baseTy,
SourceRange baseRange,
Identifier name,
SourceLoc nameLoc);
};
/// Generic type resolver that maps any generic type parameter type that
/// has an underlying archetype to its corresponding archetype.
///
/// This generic type resolver replaces generic type parameter types that
/// have archetypes with their archetypes, and leaves all other generic
/// type parameter types unchanged. It is used for the initial type-checks of
/// generic functions (and other generic declarations).
///
/// FIXME: This is not a long-term solution.
class PartialGenericTypeToArchetypeResolver : public GenericTypeResolver {
virtual Type resolveGenericTypeParamType(GenericTypeParamType *gp);
virtual AssociatedTypeDecl *resolveDependentMemberType(Type baseTy,
SourceRange baseRange,
Identifier name,
SourceLoc nameLoc);
};
} // end namespace swift
#endif

View File

@@ -15,6 +15,7 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "TypeChecker.h" #include "TypeChecker.h"
#include "GenericTypeResolver.h"
#include "swift/AST/ArchetypeBuilder.h" #include "swift/AST/ArchetypeBuilder.h"
#include "swift/AST/ASTVisitor.h" #include "swift/AST/ASTVisitor.h"
#include "swift/AST/ASTWalker.h" #include "swift/AST/ASTWalker.h"
@@ -1320,12 +1321,13 @@ public:
} }
bool semaFuncParamPatterns(DeclContext *dc, bool semaFuncParamPatterns(DeclContext *dc,
ArrayRef<Pattern*> paramPatterns) { ArrayRef<Pattern*> paramPatterns,
GenericTypeResolver *resolver) {
bool badType = false; bool badType = false;
for (Pattern *P : paramPatterns) { for (Pattern *P : paramPatterns) {
if (P->hasType()) if (P->hasType())
continue; continue;
if (TC.typeCheckPattern(P, dc, false)) { if (TC.typeCheckPattern(P, dc, false, false, resolver)) {
badType = true; badType = true;
continue; continue;
} }
@@ -1375,21 +1377,26 @@ public:
return Info; return Info;
} }
void semaFuncDecl(FuncDecl *FD, bool consumeAttributes) { void semaFuncDecl(FuncDecl *FD, bool consumeAttributes,
GenericTypeResolver *resolver) {
if (FD->hasType()) if (FD->hasType())
return; return;
bool badType = false; bool badType = false;
if (!FD->getBodyResultTypeLoc().isNull()) { if (!FD->getBodyResultTypeLoc().isNull()) {
if (TC.validateType(FD->getBodyResultTypeLoc())) { if (TC.validateType(FD->getBodyResultTypeLoc(),
/*allowUnboundGenerics=*/false,
resolver)) {
badType = true; badType = true;
} }
} }
badType = badType =
badType || semaFuncParamPatterns(FD, FD->getArgParamPatterns()); badType || semaFuncParamPatterns(FD, FD->getArgParamPatterns(),
resolver);
badType = badType =
badType || semaFuncParamPatterns(FD, FD->getBodyParamPatterns()); badType || semaFuncParamPatterns(FD, FD->getBodyParamPatterns(),
resolver);
if (badType) { if (badType) {
FD->setType(ErrorType::get(TC.Context)); FD->setType(ErrorType::get(TC.Context));
@@ -1551,10 +1558,12 @@ public:
checkGenericParamList(*builder, gp, TC); checkGenericParamList(*builder, gp, TC);
} }
semaFuncDecl(FD, /*consumeAttributes=*/!builder);
// If we have generic parameters, create archetypes now. // If we have generic parameters, create archetypes now.
if (builder) { if (builder) {
// Type check the function declaration.
PartialGenericTypeToArchetypeResolver resolver;
semaFuncDecl(FD, /*consumeAttributes=*/false, &resolver);
// Infer requirements from the parameters of the function. // Infer requirements from the parameters of the function.
for (auto pattern : FD->getArgParamPatterns()) { for (auto pattern : FD->getArgParamPatterns()) {
builder->inferRequirements(pattern); builder->inferRequirements(pattern);
@@ -1564,42 +1573,47 @@ public:
if (auto resultType = FD->getBodyResultTypeLoc().getTypeRepr()) if (auto resultType = FD->getBodyResultTypeLoc().getTypeRepr())
builder->inferRequirements(resultType); builder->inferRequirements(resultType);
// Assign archetypes. // Revert all of the types within the signature of the
finalizeGenericParamList(*builder, FD->getGenericParams(), FD, TC); 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. // Go through and revert all of the dependent types we computed.
revertSignature();
// Revert the result type. // Assign archetypes.
if (!FD->getBodyResultTypeLoc().isNull()) { finalizeGenericParamList(*builder, FD->getGenericParams(), FD, TC);
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();
// Type check the parameters and return type again, now with archetypes.
semaFuncDecl(FD, /*consumeAttributes=*/true);
// The second type check should have created a non-dependent type.
assert(!FD->getType()->isDependentType());
} }
// Type check the parameters and return type again, now with archetypes.
GenericTypeToArchetypeResolver resolver;
semaFuncDecl(FD, /*consumeAttributes=*/true, &resolver);
// This type check should have created a non-dependent type.
assert(!FD->getType()->isDependentType());
validateAttributes(TC, FD); validateAttributes(TC, FD);
// A method is ObjC-compatible if it's explicitly [objc], a member of an // A method is ObjC-compatible if it's explicitly [objc], a member of an

View File

@@ -14,8 +14,55 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "TypeChecker.h" #include "TypeChecker.h"
#include "GenericTypeResolver.h"
using namespace swift; using namespace swift;
Type GenericTypeToArchetypeResolver::resolveGenericTypeParamType(
GenericTypeParamType *gp) {
auto gpDecl = gp->getDecl();
assert(gpDecl && "Missing generic parameter declaration");
auto archetype = gpDecl->getArchetype();
assert(archetype && "Missing archetype for generic parameter");
return archetype;
}
AssociatedTypeDecl *
GenericTypeToArchetypeResolver::resolveDependentMemberType(
Type baseTy,
SourceRange baseRange,
Identifier name,
SourceLoc nameLoc) {
llvm_unreachable("Dependent type after archetype substitution");
}
Type PartialGenericTypeToArchetypeResolver::resolveGenericTypeParamType(
GenericTypeParamType *gp) {
auto gpDecl = gp->getDecl();
if (!gpDecl)
return Type(gp);
auto archetype = gpDecl->getArchetype();
if (!archetype)
return Type(gp);
return archetype;
}
AssociatedTypeDecl *
PartialGenericTypeToArchetypeResolver::resolveDependentMemberType(
Type baseTy,
SourceRange baseRange,
Identifier name,
SourceLoc nameLoc) {
// We don't have enough information to find the associated type.
return nullptr;
}
SpecializeExpr * SpecializeExpr *
TypeChecker::buildSpecializeExpr(Expr *Sub, Type Ty, TypeChecker::buildSpecializeExpr(Expr *Sub, Type Ty,
const TypeSubstitutionMap &Substitutions, const TypeSubstitutionMap &Substitutions,

View File

@@ -16,6 +16,7 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "TypeChecker.h" #include "TypeChecker.h"
#include "GenericTypeResolver.h"
#include "swift/AST/Attr.h" #include "swift/AST/Attr.h"
#include "swift/AST/ExprHandle.h" #include "swift/AST/ExprHandle.h"
#include "swift/AST/ASTVisitor.h" #include "swift/AST/ASTVisitor.h"
@@ -484,13 +485,13 @@ Pattern *TypeChecker::resolvePattern(Pattern *P, DeclContext *DC) {
} }
static bool validateTypedPattern(TypeChecker &TC, TypedPattern *TP, static bool validateTypedPattern(TypeChecker &TC, TypedPattern *TP,
bool isVararg) { bool isVararg, GenericTypeResolver *resolver) {
if (TP->hasType()) if (TP->hasType())
return TP->getType()->is<ErrorType>(); return TP->getType()->is<ErrorType>();
bool hadError = false; bool hadError = false;
TypeLoc &TL = TP->getTypeLoc(); TypeLoc &TL = TP->getTypeLoc();
if (TC.validateType(TL)) if (TC.validateType(TL, /*allowUnboundGenerics=*/false, resolver))
hadError = true; hadError = true;
Type Ty = TL.getType(); Type Ty = TL.getType();
@@ -515,13 +516,19 @@ static bool validateTypedPattern(TypeChecker &TC, TypedPattern *TP,
/// UnresolvedType. /// UnresolvedType.
bool TypeChecker::typeCheckPattern(Pattern *P, DeclContext *dc, bool TypeChecker::typeCheckPattern(Pattern *P, DeclContext *dc,
bool allowUnknownTypes, bool allowUnknownTypes,
bool isVararg) { bool isVararg,
GenericTypeResolver *resolver) {
// Make sure we always have a resolver to use.
PartialGenericTypeToArchetypeResolver defaultResolver;
if (!resolver)
resolver = &defaultResolver;
switch (P->getKind()) { switch (P->getKind()) {
// Type-check paren patterns by checking the sub-pattern and // Type-check paren patterns by checking the sub-pattern and
// propagating that type out. // propagating that type out.
case PatternKind::Paren: { case PatternKind::Paren: {
Pattern *SP = cast<ParenPattern>(P)->getSubPattern(); Pattern *SP = cast<ParenPattern>(P)->getSubPattern();
if (typeCheckPattern(SP, dc, allowUnknownTypes)) { if (typeCheckPattern(SP, dc, allowUnknownTypes, false, resolver)) {
P->setType(ErrorType::get(Context)); P->setType(ErrorType::get(Context));
return true; return true;
} }
@@ -534,8 +541,9 @@ bool TypeChecker::typeCheckPattern(Pattern *P, DeclContext *dc,
// that type. // that type.
case PatternKind::Typed: { case PatternKind::Typed: {
TypedPattern *TP = cast<TypedPattern>(P); TypedPattern *TP = cast<TypedPattern>(P);
bool hadError = validateTypedPattern(*this, TP, isVararg); bool hadError = validateTypedPattern(*this, TP, isVararg, resolver);
hadError |= coerceToType(TP->getSubPattern(), dc, P->getType()); hadError |= coerceToType(TP->getSubPattern(), dc, P->getType(), false,
resolver);
return hadError; return hadError;
} }
@@ -568,7 +576,7 @@ bool TypeChecker::typeCheckPattern(Pattern *P, DeclContext *dc,
TuplePatternElt &elt = tuplePat->getFields()[i]; TuplePatternElt &elt = tuplePat->getFields()[i];
Pattern *pattern = elt.getPattern(); Pattern *pattern = elt.getPattern();
bool isVararg = tuplePat->hasVararg() && i == e-1; bool isVararg = tuplePat->hasVararg() && i == e-1;
if (typeCheckPattern(pattern, dc, allowUnknownTypes, isVararg)) { if (typeCheckPattern(pattern, dc, allowUnknownTypes, isVararg, resolver)){
hadError = true; hadError = true;
continue; continue;
} }
@@ -603,21 +611,23 @@ bool TypeChecker::typeCheckPattern(Pattern *P, DeclContext *dc,
/// Perform top-down type coercion on the given pattern. /// Perform top-down type coercion on the given pattern.
bool TypeChecker::coerceToType(Pattern *P, DeclContext *dc, Type type, bool TypeChecker::coerceToType(Pattern *P, DeclContext *dc, Type type,
bool isVararg) { bool isVararg, GenericTypeResolver *resolver) {
switch (P->getKind()) { switch (P->getKind()) {
// For parens and vars, just set the type annotation and propagate inwards. // For parens and vars, just set the type annotation and propagate inwards.
case PatternKind::Paren: case PatternKind::Paren:
P->setType(type); P->setType(type);
return coerceToType(cast<ParenPattern>(P)->getSubPattern(), dc, type); return coerceToType(cast<ParenPattern>(P)->getSubPattern(), dc, type,
false, resolver);
case PatternKind::Var: case PatternKind::Var:
P->setType(type); P->setType(type);
return coerceToType(cast<VarPattern>(P)->getSubPattern(), dc, type); return coerceToType(cast<VarPattern>(P)->getSubPattern(), dc, type,
false, resolver);
// If we see an explicit type annotation, coerce the sub-pattern to // If we see an explicit type annotation, coerce the sub-pattern to
// that type. // that type.
case PatternKind::Typed: { case PatternKind::Typed: {
TypedPattern *TP = cast<TypedPattern>(P); TypedPattern *TP = cast<TypedPattern>(P);
bool hadError = validateTypedPattern(*this, TP, isVararg); bool hadError = validateTypedPattern(*this, TP, isVararg, resolver);
if (!hadError) { if (!hadError) {
if (!type->isEqual(TP->getType()) && !type->is<ErrorType>()) { if (!type->isEqual(TP->getType()) && !type->is<ErrorType>()) {
// Complain if the types don't match exactly. // Complain if the types don't match exactly.
@@ -627,7 +637,8 @@ bool TypeChecker::coerceToType(Pattern *P, DeclContext *dc, Type type,
} }
} }
hadError |= coerceToType(TP->getSubPattern(), dc, TP->getType()); hadError |= coerceToType(TP->getSubPattern(), dc, TP->getType(), false,
resolver);
return hadError; return hadError;
} }
@@ -683,7 +694,7 @@ bool TypeChecker::coerceToType(Pattern *P, DeclContext *dc, Type type,
else else
CoercionType = tupleTy->getFields()[i].getType(); CoercionType = tupleTy->getFields()[i].getType();
hadError |= coerceToType(pattern, dc, CoercionType, isVararg); hadError |= coerceToType(pattern, dc, CoercionType, isVararg, resolver);
// Type-check the initialization expression. // Type-check the initialization expression.
if (ExprHandle *initHandle = elt.getInit()) { if (ExprHandle *initHandle = elt.getInit()) {
@@ -772,7 +783,7 @@ bool TypeChecker::coerceToType(Pattern *P, DeclContext *dc, Type type,
elt->getArgumentType()); elt->getArgumentType());
else else
elementType = TupleType::getEmpty(Context); elementType = TupleType::getEmpty(Context);
if (coerceToType(OP->getSubPattern(), dc, elementType)) if (coerceToType(OP->getSubPattern(), dc, elementType, false, resolver))
return true; return true;
} }
OP->setType(type); OP->setType(type);
@@ -842,7 +853,8 @@ bool TypeChecker::coerceToType(Pattern *P, DeclContext *dc, Type type,
} }
// Coerce the subpattern. // Coerce the subpattern.
if (coerceToType(elt.getSubPattern(), dc, elt.getProperty()->getType())) if (coerceToType(elt.getSubPattern(), dc, elt.getProperty()->getType(),
false, resolver))
return true; return true;
} }
NP->setType(patTy); NP->setType(patTy);

View File

@@ -16,6 +16,8 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "TypeChecker.h" #include "TypeChecker.h"
#include "GenericTypeResolver.h"
#include "swift/AST/ASTWalker.h" #include "swift/AST/ASTWalker.h"
#include "swift/AST/ExprHandle.h" #include "swift/AST/ExprHandle.h"
#include "swift/AST/NameLookup.h" #include "swift/AST/NameLookup.h"
@@ -25,6 +27,8 @@
#include "llvm/ADT/Twine.h" #include "llvm/ADT/Twine.h"
using namespace swift; using namespace swift;
GenericTypeResolver::~GenericTypeResolver() { }
Type TypeChecker::getArraySliceType(SourceLoc loc, Type elementType) { Type TypeChecker::getArraySliceType(SourceLoc loc, Type elementType) {
if (!Context.getSliceDecl()) { if (!Context.getSliceDecl()) {
diagnose(loc, diag::sugar_type_not_found, 0); diagnose(loc, diag::sugar_type_not_found, 0);
@@ -231,7 +235,8 @@ static void diagnoseUnboundGenericType(TypeChecker &tc, Type ty,SourceLoc loc) {
static Type resolveTypeDecl(TypeChecker &TC, TypeDecl *typeDecl, SourceLoc loc, static Type resolveTypeDecl(TypeChecker &TC, TypeDecl *typeDecl, SourceLoc loc,
DeclContext *dc, DeclContext *dc,
MutableArrayRef<TypeRepr *> genericArgs, MutableArrayRef<TypeRepr *> genericArgs,
bool allowUnboundGenerics) { bool allowUnboundGenerics,
GenericTypeResolver *resolver) {
TC.validateDecl(typeDecl); TC.validateDecl(typeDecl);
Type type; Type type;
@@ -249,11 +254,9 @@ static Type resolveTypeDecl(TypeChecker &TC, TypeDecl *typeDecl, SourceLoc loc,
return ErrorType::get(TC.Context); return ErrorType::get(TC.Context);
} }
// If we found a generic parameter, map to the archetype if there is one. // If we found a generic parameter, try to resolve it.
if (auto genericParam = type->getAs<GenericTypeParamType>()) { if (auto genericParam = type->getAs<GenericTypeParamType>()) {
if (auto archetype = genericParam->getDecl()->getArchetype()) { type = resolver->resolveGenericTypeParamType(genericParam);
type = archetype;
}
} }
if (!genericArgs.empty()) { if (!genericArgs.empty()) {
@@ -268,7 +271,8 @@ static Type resolveTypeDecl(TypeChecker &TC, TypeDecl *typeDecl, SourceLoc loc,
static llvm::PointerUnion<Type, Module *> static llvm::PointerUnion<Type, Module *>
resolveIdentTypeComponent(TypeChecker &TC, resolveIdentTypeComponent(TypeChecker &TC,
MutableArrayRef<IdentTypeRepr::Component> components, MutableArrayRef<IdentTypeRepr::Component> components,
bool allowUnboundGenerics) { bool allowUnboundGenerics,
GenericTypeResolver *resolver) {
auto &comp = components.back(); auto &comp = components.back();
if (!comp.isBound()) { if (!comp.isBound()) {
auto parentComps = components.slice(0, components.size()-1); auto parentComps = components.slice(0, components.size()-1);
@@ -307,7 +311,8 @@ resolveIdentTypeComponent(TypeChecker &TC,
Type type = resolveTypeDecl(TC, typeDecl, comp.getIdLoc(), Type type = resolveTypeDecl(TC, typeDecl, comp.getIdLoc(),
dc, comp.getGenericArgs(), dc, comp.getGenericArgs(),
allowUnboundGenerics); allowUnboundGenerics,
resolver);
if (type->is<ErrorType>()) { if (type->is<ErrorType>()) {
comp.setValue(type); comp.setValue(type);
return type; return type;
@@ -363,7 +368,8 @@ resolveIdentTypeComponent(TypeChecker &TC,
} else { } else {
llvm::PointerUnion<Type, Module *> llvm::PointerUnion<Type, Module *>
parent = resolveIdentTypeComponent(TC, parentComps, parent = resolveIdentTypeComponent(TC, parentComps,
allowUnboundGenerics); allowUnboundGenerics,
resolver);
// If the last resolved component is a type, perform member type lookup. // If the last resolved component is a type, perform member type lookup.
if (parent.is<Type>()) { if (parent.is<Type>()) {
auto parentTy = parent.get<Type>(); auto parentTy = parent.get<Type>();
@@ -372,10 +378,26 @@ resolveIdentTypeComponent(TypeChecker &TC,
// If the parent is a dependent type, the member is a dependent member. // If the parent is a dependent type, the member is a dependent member.
if (parentTy->isDependentType()) { if (parentTy->isDependentType()) {
// Form a dependent member type. Type memberType;
Type memberType = DependentMemberType::get(parentTy,
comp.getIdentifier(), // Try to resolve the dependent member type to a specific associated
TC.Context); // type.
// FIXME: Want the end of the back range.
SourceRange parentRange(parentComps.front().getIdLoc(),
parentComps.back().getIdLoc());
if (auto assocType = resolver->resolveDependentMemberType(
parentTy,
parentRange,
comp.getIdentifier(),
comp.getIdLoc())) {
memberType = DependentMemberType::get(parentTy,
assocType,
TC.Context);
} else {
memberType = DependentMemberType::get(parentTy,
comp.getIdentifier(),
TC.Context);
}
if (!comp.getGenericArgs().empty()) { if (!comp.getGenericArgs().empty()) {
// FIXME: Highlight generic arguments and introduce a Fix-It to // FIXME: Highlight generic arguments and introduce a Fix-It to
@@ -490,17 +512,22 @@ resolveIdentTypeComponent(TypeChecker &TC,
} }
Type type = resolveTypeDecl(TC, typeDecl, comp.getIdLoc(), nullptr, Type type = resolveTypeDecl(TC, typeDecl, comp.getIdLoc(), nullptr,
comp.getGenericArgs(), allowUnboundGenerics); comp.getGenericArgs(), allowUnboundGenerics,
resolver);
comp.setValue(type); comp.setValue(type);
return type; return type;
} }
/// \brief Returns a valid type or ErrorType in case of an error. /// \brief Returns a valid type or ErrorType in case of an error.
static Type resolveIdentifierType(TypeChecker &TC, IdentTypeRepr* IdType, static Type resolveIdentifierType(TypeChecker &TC, IdentTypeRepr* IdType,
bool allowUnboundGenerics) { bool allowUnboundGenerics,
GenericTypeResolver *resolver) {
assert(resolver && "Missing generic type resolver");
llvm::PointerUnion<Type, Module *> llvm::PointerUnion<Type, Module *>
result = resolveIdentTypeComponent(TC, IdType->Components, result = resolveIdentTypeComponent(TC, IdType->Components,
allowUnboundGenerics); allowUnboundGenerics,
resolver);
if (auto mod = result.dyn_cast<Module*>()) { if (auto mod = result.dyn_cast<Module*>()) {
TC.diagnose(IdType->Components.back().getIdLoc(), TC.diagnose(IdType->Components.back().getIdLoc(),
diag::use_module_as_type, mod->Name); diag::use_module_as_type, mod->Name);
@@ -512,7 +539,8 @@ static Type resolveIdentifierType(TypeChecker &TC, IdentTypeRepr* IdType,
return result.get<Type>(); return result.get<Type>();
} }
bool TypeChecker::validateType(TypeLoc &Loc, bool allowUnboundGenerics) { bool TypeChecker::validateType(TypeLoc &Loc, bool allowUnboundGenerics,
GenericTypeResolver *resolver) {
// FIXME: Verify that these aren't circular and infinite size. // FIXME: Verify that these aren't circular and infinite size.
// If we've already validated this type, don't do so again. // If we've already validated this type, don't do so again.
@@ -520,7 +548,8 @@ bool TypeChecker::validateType(TypeLoc &Loc, bool allowUnboundGenerics) {
return Loc.isError(); return Loc.isError();
if (Loc.getType().isNull()) { if (Loc.getType().isNull()) {
Loc.setType(resolveType(Loc.getTypeRepr(), allowUnboundGenerics), true); Loc.setType(resolveType(Loc.getTypeRepr(), allowUnboundGenerics, resolver),
true);
return Loc.isError(); return Loc.isError();
} }
@@ -528,9 +557,15 @@ bool TypeChecker::validateType(TypeLoc &Loc, bool allowUnboundGenerics) {
return Loc.isError(); return Loc.isError();
} }
Type TypeChecker::resolveType(TypeRepr *TyR, bool allowUnboundGenerics) { Type TypeChecker::resolveType(TypeRepr *TyR, bool allowUnboundGenerics,
GenericTypeResolver *resolver) {
PrettyStackTraceTypeRepr stackTrace(Context, "resolving", TyR); PrettyStackTraceTypeRepr stackTrace(Context, "resolving", TyR);
// Make sure we always have a resolver to use.
PartialGenericTypeToArchetypeResolver defaultResolver;
if (!resolver)
resolver = &defaultResolver;
assert(TyR && "Cannot validate null TypeReprs!"); assert(TyR && "Cannot validate null TypeReprs!");
switch (TyR->getKind()) { switch (TyR->getKind()) {
case TypeReprKind::Error: case TypeReprKind::Error:
@@ -541,7 +576,9 @@ Type TypeChecker::resolveType(TypeRepr *TyR, bool allowUnboundGenerics) {
auto AttrTyR = cast<AttributedTypeRepr>(TyR); auto AttrTyR = cast<AttributedTypeRepr>(TyR);
DeclAttributes attrs = AttrTyR->getAttrs(); DeclAttributes attrs = AttrTyR->getAttrs();
assert(!attrs.empty()); assert(!attrs.empty());
Ty = resolveType(AttrTyR->getTypeRepr()); Ty = resolveType(AttrTyR->getTypeRepr(),
/*FIXME:allowUnboundGenerics=*/false,
resolver);
if (Ty->is<ErrorType>()) if (Ty->is<ErrorType>())
return Ty; return Ty;
@@ -635,14 +672,19 @@ Type TypeChecker::resolveType(TypeRepr *TyR, bool allowUnboundGenerics) {
case TypeReprKind::Ident: case TypeReprKind::Ident:
return resolveIdentifierType(*this, cast<IdentTypeRepr>(TyR), return resolveIdentifierType(*this, cast<IdentTypeRepr>(TyR),
allowUnboundGenerics); allowUnboundGenerics,
resolver);
case TypeReprKind::Function: { case TypeReprKind::Function: {
auto FnTyR = cast<FunctionTypeRepr>(TyR); auto FnTyR = cast<FunctionTypeRepr>(TyR);
Type inputTy = resolveType(FnTyR->getArgsTypeRepr()); Type inputTy = resolveType(FnTyR->getArgsTypeRepr(),
/*FIXME:allowUnboundGenerics=*/false,
resolver);
if (inputTy->is<ErrorType>()) if (inputTy->is<ErrorType>())
return inputTy; return inputTy;
Type outputTy = resolveType(FnTyR->getResultTypeRepr()); Type outputTy = resolveType(FnTyR->getResultTypeRepr(),
/*FIXME:allowUnboundGenerics=*/false,
resolver);
if (outputTy->is<ErrorType>()) if (outputTy->is<ErrorType>())
return outputTy; return outputTy;
return FunctionType::get(inputTy, outputTy, Context); return FunctionType::get(inputTy, outputTy, Context);
@@ -651,7 +693,9 @@ Type TypeChecker::resolveType(TypeRepr *TyR, bool allowUnboundGenerics) {
case TypeReprKind::Array: { case TypeReprKind::Array: {
// FIXME: diagnose non-materializability of element type! // FIXME: diagnose non-materializability of element type!
auto ArrTyR = cast<ArrayTypeRepr>(TyR); auto ArrTyR = cast<ArrayTypeRepr>(TyR);
Type baseTy = resolveType(ArrTyR->getBase()); Type baseTy = resolveType(ArrTyR->getBase(),
/*FIXME:allowUnboundGenerics=*/false,
resolver);
if (baseTy->is<ErrorType>()) if (baseTy->is<ErrorType>())
return baseTy; return baseTy;
@@ -673,7 +717,9 @@ Type TypeChecker::resolveType(TypeRepr *TyR, bool allowUnboundGenerics) {
case TypeReprKind::Optional: { case TypeReprKind::Optional: {
// FIXME: diagnose non-materializability of element type! // FIXME: diagnose non-materializability of element type!
auto optTyR = cast<OptionalTypeRepr>(TyR); auto optTyR = cast<OptionalTypeRepr>(TyR);
Type baseTy = resolveType(optTyR->getBase()); Type baseTy = resolveType(optTyR->getBase(),
/*FIXME:allowUnboundGenerics=*/false,
resolver);
if (baseTy->is<ErrorType>()) if (baseTy->is<ErrorType>())
return baseTy; return baseTy;
@@ -689,12 +735,16 @@ Type TypeChecker::resolveType(TypeRepr *TyR, bool allowUnboundGenerics) {
SmallVector<TupleTypeElt, 8> Elements; SmallVector<TupleTypeElt, 8> Elements;
for (auto tyR : TupTyR->getElements()) { for (auto tyR : TupTyR->getElements()) {
if (NamedTypeRepr *namedTyR = dyn_cast<NamedTypeRepr>(tyR)) { if (NamedTypeRepr *namedTyR = dyn_cast<NamedTypeRepr>(tyR)) {
Type ty = resolveType(namedTyR->getTypeRepr()); Type ty = resolveType(namedTyR->getTypeRepr(),
/*FIXME:allowUnboundGenerics=*/false,
resolver);
if (ty->is<ErrorType>()) if (ty->is<ErrorType>())
return ty; return ty;
Elements.push_back(TupleTypeElt(ty, namedTyR->getName())); Elements.push_back(TupleTypeElt(ty, namedTyR->getName()));
} else { } else {
Type ty = resolveType(tyR); Type ty = resolveType(tyR,
/*FIXME:allowUnboundGenerics=*/false,
resolver);
if (ty->is<ErrorType>()) if (ty->is<ErrorType>())
return ty; return ty;
Elements.push_back(TupleTypeElt(ty)); Elements.push_back(TupleTypeElt(ty));
@@ -721,7 +771,8 @@ Type TypeChecker::resolveType(TypeRepr *TyR, bool allowUnboundGenerics) {
auto ProtTyR = cast<ProtocolCompositionTypeRepr>(TyR); auto ProtTyR = cast<ProtocolCompositionTypeRepr>(TyR);
SmallVector<Type, 4> ProtocolTypes; SmallVector<Type, 4> ProtocolTypes;
for (auto tyR : ProtTyR->getProtocols()) { for (auto tyR : ProtTyR->getProtocols()) {
Type ty = resolveType(tyR); Type ty = resolveType(tyR, /*FIXME:allowUnboundGenerics=*/false,
resolver);
if (ty->is<ErrorType>()) if (ty->is<ErrorType>())
return ty; return ty;
if (!ty->isExistentialType()) { if (!ty->isExistentialType()) {
@@ -747,7 +798,9 @@ Type TypeChecker::resolveType(TypeRepr *TyR, bool allowUnboundGenerics) {
} }
case TypeReprKind::MetaType: { case TypeReprKind::MetaType: {
Type ty = resolveType(cast<MetaTypeTypeRepr>(TyR)->getBase()); Type ty = resolveType(cast<MetaTypeTypeRepr>(TyR)->getBase(),
/*FIXME:allowUnboundGenerics=*/false,
resolver);
if (ty->is<ErrorType>()) if (ty->is<ErrorType>())
return ty; return ty;
return MetaTypeType::get(ty, Context); return MetaTypeType::get(ty, Context);

View File

@@ -29,6 +29,7 @@
namespace swift { namespace swift {
class GenericTypeResolver;
class TypeChecker; class TypeChecker;
/// \brief A mapping from substitutable types to the protocol-conformance /// \brief A mapping from substitutable types to the protocol-conformance
@@ -171,16 +172,28 @@ public:
/// in places where the generic arguments will be deduced, e.g., within an /// in places where the generic arguments will be deduced, e.g., within an
/// expression. /// expression.
/// ///
/// \param resolver A resolver for generic types. If none is supplied, this
/// routine will create a \c PartialGenericTypeToArchetypeResolver to use.
///
/// \returns true if type validation failed, or false otherwise. /// \returns true if type validation failed, or false otherwise.
bool validateType(TypeLoc &Loc, bool allowUnboundGenerics = false); bool validateType(TypeLoc &Loc, bool allowUnboundGenerics = false,
GenericTypeResolver *resolver = nullptr);
/// \brief Resolves a TypeRepr to a type. /// \brief Resolves a TypeRepr to a type.
/// ///
/// Performs name binding, checking of generic arguments, and so on in order /// Performs name binding, checking of generic arguments, and so on in order
/// to create a well-formed type. /// to create a well-formed type.
/// ///
/// \param TyR The type representation to check.
///
/// \param allowUnboundGenerics Whether to allow unbound generic types.
///
/// \param resolver A resolver for generic types. If none is supplied, this
/// routine will create a \c PartialGenericTypeToArchetypeResolver to use.
///
/// \returns a well-formed type or an ErrorType in case of an error. /// \returns a well-formed type or an ErrorType in case of an error.
Type resolveType(TypeRepr *TyR, bool allowUnboundGenerics = false); Type resolveType(TypeRepr *TyR, bool allowUnboundGenerics = false,
GenericTypeResolver *resolver = nullptr);
void validateDecl(ValueDecl *D, bool resolveTypeParams = false); void validateDecl(ValueDecl *D, bool resolveTypeParams = false);
@@ -440,8 +453,10 @@ public:
bool typeCheckPattern(Pattern *P, DeclContext *dc, bool typeCheckPattern(Pattern *P, DeclContext *dc,
bool allowUnknownTypes, bool allowUnknownTypes,
bool isVararg = false); bool isVararg = false,
bool coerceToType(Pattern *P, DeclContext *dc, Type Ty, bool isVararg =false); GenericTypeResolver *resolver = nullptr);
bool coerceToType(Pattern *P, DeclContext *dc, Type Ty, bool isVararg = false,
GenericTypeResolver *resolver = nullptr);
bool typeCheckExprPattern(ExprPattern *EP, DeclContext *DC, bool typeCheckExprPattern(ExprPattern *EP, DeclContext *DC,
Type type); Type type);

View File

@@ -1898,12 +1898,14 @@ Type ModuleFile::getType(TypeID TID) {
case decls_block::DEPENDENT_MEMBER_TYPE: { case decls_block::DEPENDENT_MEMBER_TYPE: {
TypeID baseID; TypeID baseID;
IdentifierID nameID; DeclID assocTypeID;
decls_block::DependentMemberTypeLayout::readRecord(scratch, baseID, nameID); decls_block::DependentMemberTypeLayout::readRecord(scratch, baseID,
typeOrOffset = DependentMemberType::get(getType(baseID), assocTypeID);
getIdentifier(nameID), typeOrOffset = DependentMemberType::get(
ctx); getType(baseID),
cast<AssociatedTypeDecl>(getDecl(assocTypeID)),
ctx);
break; break;
} }

View File

@@ -346,7 +346,7 @@ namespace decls_block {
using DependentMemberTypeLayout = BCRecordLayout< using DependentMemberTypeLayout = BCRecordLayout<
DEPENDENT_MEMBER_TYPE, DEPENDENT_MEMBER_TYPE,
TypeIDField, // base type TypeIDField, // base type
IdentifierIDField // member name DeclIDField // associated type decl
>; >;
using NominalTypeLayout = BCRecordLayout< using NominalTypeLayout = BCRecordLayout<
NOMINAL_TYPE, NOMINAL_TYPE,

View File

@@ -1525,10 +1525,11 @@ void Serializer::writeType(Type ty) {
auto dependent = cast<DependentMemberType>(ty.getPointer()); auto dependent = cast<DependentMemberType>(ty.getPointer());
unsigned abbrCode = DeclTypeAbbrCodes[DependentMemberTypeLayout::Code]; unsigned abbrCode = DeclTypeAbbrCodes[DependentMemberTypeLayout::Code];
assert(dependent->getAssocType() && "Unchecked dependent member type");
DependentMemberTypeLayout::emitRecord( DependentMemberTypeLayout::emitRecord(
Out, ScratchRecord, abbrCode, Out, ScratchRecord, abbrCode,
addTypeRef(dependent->getBase()), addTypeRef(dependent->getBase()),
addIdentifierRef(dependent->getName())); addDeclRef(dependent->getAssocType()));
break; break;
} }