Skip to content

[Type checker] Use DependentMemberType instead of type variables for nested types. #5626

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Nov 6, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 1 addition & 14 deletions include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,6 @@ enum class KnownFoundationEntity {
/// entity name.
Optional<KnownFoundationEntity> getKnownFoundationEntity(StringRef name);

/// Callback function used when referring to a type member of a given
/// type variable.
typedef std::function<Type(TypeVariableType *, AssociatedTypeDecl *)>
GetTypeVariableMemberCallback;

/// \brief Introduces a new constraint checker arena, whose lifetime is
/// tied to the lifetime of this RAII object.
class ConstraintCheckerArenaRAII {
Expand All @@ -142,8 +137,7 @@ class ConstraintCheckerArenaRAII {
/// \param allocator The allocator used for allocating any data that
/// goes into the constraint checker arena.
ConstraintCheckerArenaRAII(ASTContext &self,
llvm::BumpPtrAllocator &allocator,
GetTypeVariableMemberCallback getTypeMember);
llvm::BumpPtrAllocator &allocator);

ConstraintCheckerArenaRAII(const ConstraintCheckerArenaRAII &) = delete;
ConstraintCheckerArenaRAII(ConstraintCheckerArenaRAII &&) = delete;
Expand Down Expand Up @@ -519,13 +513,6 @@ class ASTContext {
const CanType TheIEEE128Type; /// 128-bit IEEE floating point
const CanType ThePPC128Type; /// 128-bit PowerPC 2xDouble

/// Retrieve a type member of the given base type variable.
///
/// Note that this routine is only usable when a constraint system
/// is active.
Type getTypeVariableMemberType(TypeVariableType *baseTypeVar,
AssociatedTypeDecl *assocType);

/// Adds a search path to SearchPathOpts, unless it is already present.
///
/// Does any proper bookkeeping to keep all module loaders up to date as well.
Expand Down
30 changes: 13 additions & 17 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,12 +330,8 @@ struct ASTContext::Implementation {
/// The allocator used for all allocations within this arena.
llvm::BumpPtrAllocator &Allocator;

/// Callback used to get a type member of a type variable.
GetTypeVariableMemberCallback GetTypeMember;

ConstraintSolverArena(llvm::BumpPtrAllocator &allocator,
GetTypeVariableMemberCallback &&getTypeMember)
: Allocator(allocator), GetTypeMember(std::move(getTypeMember)) { }
ConstraintSolverArena(llvm::BumpPtrAllocator &allocator)
: Allocator(allocator) { }

ConstraintSolverArena(const ConstraintSolverArena &) = delete;
ConstraintSolverArena(ConstraintSolverArena &&) = delete;
Expand Down Expand Up @@ -369,14 +365,11 @@ ASTContext::Implementation::~Implementation() {
}

ConstraintCheckerArenaRAII::
ConstraintCheckerArenaRAII(ASTContext &self, llvm::BumpPtrAllocator &allocator,
GetTypeVariableMemberCallback getTypeMember)
ConstraintCheckerArenaRAII(ASTContext &self, llvm::BumpPtrAllocator &allocator)
: Self(self), Data(self.Impl.CurrentConstraintSolverArena.release())
{
Self.Impl.CurrentConstraintSolverArena.reset(
new ASTContext::Implementation::ConstraintSolverArena(
allocator,
std::move(getTypeMember)));
new ASTContext::Implementation::ConstraintSolverArena(allocator));
}

ConstraintCheckerArenaRAII::~ConstraintCheckerArenaRAII() {
Expand Down Expand Up @@ -1164,12 +1157,6 @@ void ASTContext::setSubstitutions(TypeBase* type,
boundGenericSubstitutions[{type, gpContext}] = Subs;
}

Type ASTContext::getTypeVariableMemberType(TypeVariableType *baseTypeVar,
AssociatedTypeDecl *assocType) {
auto &arena = *Impl.CurrentConstraintSolverArena;
return arena.GetTypeMember(baseTypeVar, assocType);
}

void ASTContext::addSearchPath(StringRef searchPath, bool isFramework) {
OptionSet<SearchPathKind> &loaded = Impl.SearchPathsSet[searchPath];
auto kind = isFramework ? SearchPathKind::Framework : SearchPathKind::Import;
Expand Down Expand Up @@ -1386,6 +1373,15 @@ ASTContext::getBehaviorConformance(Type conformingType,
auto conformance = new (*this, AllocationArena::Permanent)
NormalProtocolConformance(conformingType, conformingInterfaceType,
protocol, loc, storage, state);

if (auto nominal = conformingInterfaceType->getAnyNominal()) {
// Note: this is an egregious hack. The conformances need to be associated
// with the actual storage declarations.
SmallVector<ProtocolConformance *, 2> conformances;
if (!nominal->lookupConformance(nominal->getModuleContext(), protocol,
conformances))
nominal->registerProtocolConformance(conformance);
}
return conformance;
}

Expand Down
19 changes: 9 additions & 10 deletions lib/AST/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -586,28 +586,24 @@ TypeBase::gatherAllSubstitutions(Module *module,
// The type itself contains substitutions up to the innermost
// non-type context.
CanType parent(canon);
auto *parentDC = gpContext;
ArrayRef<GenericTypeParamType *> genericParams =
genericSig->getGenericParams();
unsigned lastGenericIndex = genericParams.size();
while (parent) {
if (auto boundGeneric = dyn_cast<BoundGenericType>(parent)) {
auto genericSig = parentDC->getGenericSignatureOfContext();
unsigned index = 0;

assert(boundGeneric->getGenericArgs().size() ==
genericSig->getInnermostGenericParams().size());

unsigned index = lastGenericIndex - boundGeneric->getGenericArgs().size();
for (Type arg : boundGeneric->getGenericArgs()) {
auto paramTy = genericSig->getInnermostGenericParams()[index++];
auto paramTy = genericParams[index++];
substitutions[paramTy->getCanonicalType().getPointer()] = arg;
}
lastGenericIndex -= boundGeneric->getGenericArgs().size();

parent = CanType(boundGeneric->getParent());
parentDC = parentDC->getParent();
continue;
}

if (auto nominal = dyn_cast<NominalType>(parent)) {
parent = CanType(nominal->getParent());
parentDC = parentDC->getParent();
continue;
}

Expand All @@ -616,6 +612,9 @@ TypeBase::gatherAllSubstitutions(Module *module,

// Add forwarding substitutions from the outer context if we have
// a type nested inside a generic function.
auto *parentDC = gpContext;
while (parentDC->isTypeContext())
parentDC = parentDC->getParent();
if (auto *outerEnv = parentDC->getGenericEnvironmentOfContext())
for (auto pair : outerEnv->getInterfaceToArchetypeMap()) {
auto result = substitutions.insert(pair);
Expand Down
19 changes: 11 additions & 8 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,13 @@ class GetRValueTypeVisitor : public TypeVisitor<GetRValueTypeVisitor, Type> {
Type visitParenType(ParenType *pt) {
return ParenType::get(pt->getASTContext(), visit(pt->getUnderlyingType()));
}


Type visitSubstitutedType(SubstitutedType *st) {
return SubstitutedType::get(st->getOriginal(),
visit(st->getReplacementType()),
st->getASTContext());
}

Type visitType(TypeBase *t) {
// Other types should not structurally contain lvalues.
assert(!t->isLValueType()
Expand Down Expand Up @@ -2774,13 +2780,10 @@ static Type getMemberForBaseType(ConformanceSource conformances,
return getDependentMemberType(ErrorType::get(substBase));
}

// If the parent is a type variable, retrieve its member type
// variable.
if (auto typeVarParent = substBase->getAs<TypeVariableType>()) {
assert(assocType && "Missing associated type");
return substBase->getASTContext().getTypeVariableMemberType(typeVarParent,
assocType);
}
// If the parent is a type variable or a member rooted in a type variable,
// we're done.
if (substBase->isTypeVariableOrMember())
return getDependentMemberType(substBase);

// Retrieve the member type with the given name.

Expand Down
26 changes: 6 additions & 20 deletions lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1690,17 +1690,11 @@ namespace {
locator);

// Its subexpression should be convertible to a tuple (T.Element...).
// FIXME: We should really go through the conformance above to extract
// the element type, rather than just looking for the element type.
// FIXME: Member constraint is still weird here.
ConstraintLocatorBuilder builder(locator);
auto arrayElementTy = CS.getMemberType(arrayTy, elementAssocTy,
builder.withPathElement(
ConstraintLocator::Member),
/*options=*/0);
Type arrayElementTy = DependentMemberType::get(arrayTy, elementAssocTy);

// Introduce conversions from each element to the element type of the
// array.
ConstraintLocatorBuilder builder(locator);
unsigned index = 0;
for (auto element : expr->getElements()) {
CS.addConstraint(ConstraintKind::Conversion,
Expand Down Expand Up @@ -1758,18 +1752,10 @@ namespace {

// Its subexpression should be convertible to a tuple ((T.Key,T.Value)...).
ConstraintLocatorBuilder locatorBuilder(locator);
auto dictionaryKeyTy = CS.getMemberType(dictionaryTy,
keyAssocTy,
locatorBuilder.withPathElement(
ConstraintLocator::Member),
/*options=*/0);
/// FIXME: ArrayElementType is a total hack here.
auto dictionaryValueTy = CS.getMemberType(dictionaryTy,
valueAssocTy,
locatorBuilder.withPathElement(
ConstraintLocator::ArrayElementType),
/*options=*/0);

auto dictionaryKeyTy = DependentMemberType::get(dictionaryTy,
keyAssocTy);
auto dictionaryValueTy = DependentMemberType::get(dictionaryTy,
valueAssocTy);
TupleTypeElt tupleElts[2] = { TupleTypeElt(dictionaryKeyTy),
TupleTypeElt(dictionaryValueTy) };
Type elementTy = TupleType::get(tupleElts, C);
Expand Down
21 changes: 15 additions & 6 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1438,8 +1438,11 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
}
}

bool isTypeVarOrMember1 = desugar1->isTypeVariableOrMember();
bool isTypeVarOrMember2 = desugar2->isTypeVariableOrMember();

llvm::SmallVector<RestrictionOrFix, 4> conversionsOrFixes;
bool concrete = !typeVar1 && !typeVar2;
bool concrete = !isTypeVarOrMember1 && !isTypeVarOrMember2;

// If this is an argument conversion, handle it directly. The rules are
// different from normal conversions.
Expand Down Expand Up @@ -1482,9 +1485,12 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
return SolutionKind::Error;

case TypeKind::GenericTypeParam:
case TypeKind::DependentMember:
llvm_unreachable("unmapped dependent type in type checker");

case TypeKind::DependentMember:
// Nothing we can solve.
return formUnsolvedResult();

case TypeKind::TypeVariable:
case TypeKind::Archetype:
// Nothing to do here; handle type variables and archetypes below.
Expand Down Expand Up @@ -2077,7 +2083,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,

// If we should attempt fixes, add those to the list. They'll only be visited
// if there are no other possible solutions.
if (shouldAttemptFixes() && !typeVar1 && !typeVar2 &&
if (shouldAttemptFixes() && !isTypeVarOrMember1 && !isTypeVarOrMember2 &&
!flags.contains(TMF_ApplyingFix) && kind >= ConstraintKind::Conversion) {
Type objectType1 = type1->getRValueObjectType();

Expand Down Expand Up @@ -2136,8 +2142,10 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
}

if (conversionsOrFixes.empty()) {
// If one of the types is a type variable, we leave this unsolved.
if (typeVar1 || typeVar2) return formUnsolvedResult();
// If one of the types is a type variable or member thereof, we leave this
// unsolved.
if (isTypeVarOrMember1 || isTypeVarOrMember2)
return formUnsolvedResult();

return SolutionKind::Error;
}
Expand Down Expand Up @@ -2200,6 +2208,7 @@ ConstraintSystem::SolutionKind
ConstraintSystem::simplifyConstructionConstraint(
Type valueType, FunctionType *fnType, TypeMatchOptions flags,
FunctionRefKind functionRefKind, ConstraintLocator *locator) {

// Desugar the value type.
auto desugarValueType = valueType->getDesugaredType();

Expand All @@ -2223,10 +2232,10 @@ ConstraintSystem::simplifyConstructionConstraint(

case TypeKind::GenericFunction:
case TypeKind::GenericTypeParam:
case TypeKind::DependentMember:
llvm_unreachable("unmapped dependent type");

case TypeKind::TypeVariable:
case TypeKind::DependentMember:
return SolutionKind::Unsolved;

case TypeKind::Tuple: {
Expand Down
Loading