Skip to content

Commit a6c3e6f

Browse files
authored
Merge pull request #33658 from xedin/introduce-hole-type
[ConstraintSystem] Introduce a new type to represent a type hole
2 parents 02513b1 + 4847ec9 commit a6c3e6f

24 files changed

+171
-46
lines changed

include/swift/AST/TypeNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989

9090
TYPE(Error, Type)
9191
UNCHECKED_TYPE(Unresolved, Type)
92+
UNCHECKED_TYPE(Hole, Type)
9293
ABSTRACT_TYPE(Builtin, Type)
9394
ABSTRACT_TYPE(AnyBuiltinInteger, BuiltinType)
9495
BUILTIN_TYPE(BuiltinInteger, AnyBuiltinIntegerType)

include/swift/AST/Types.h

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,10 @@ class RecursiveTypeProperties {
148148
/// This type contains an OpaqueTypeArchetype.
149149
HasOpaqueArchetype = 0x400,
150150

151-
Last_Property = HasOpaqueArchetype
151+
/// This type contains a type hole.
152+
HasTypeHole = 0x800,
153+
154+
Last_Property = HasTypeHole
152155
};
153156
enum { BitWidth = countBitsUsed(Property::Last_Property) };
154157

@@ -203,6 +206,10 @@ class RecursiveTypeProperties {
203206
/// generic type?
204207
bool hasUnboundGeneric() const { return Bits & HasUnboundGeneric; }
205208

209+
/// Does a type with these properties structurally contain a
210+
/// type hole?
211+
bool hasTypeHole() const { return Bits & HasTypeHole; }
212+
206213
/// Returns the set of properties present in either set.
207214
friend RecursiveTypeProperties operator|(Property lhs, Property rhs) {
208215
return RecursiveTypeProperties(unsigned(lhs) | unsigned(rhs));
@@ -573,9 +580,7 @@ class alignas(1 << TypeAlignInBits) TypeBase {
573580
}
574581

575582
/// Determine whether this type involves a hole.
576-
bool hasHole() const {
577-
return getRecursiveProperties().hasUnresolvedType();
578-
}
583+
bool hasHole() const { return getRecursiveProperties().hasTypeHole(); }
579584

580585
/// Determine whether the type involves a context-dependent archetype.
581586
bool hasArchetype() const {
@@ -5726,6 +5731,31 @@ TypeVariableType : public TypeBase {
57265731
};
57275732
DEFINE_EMPTY_CAN_TYPE_WRAPPER(TypeVariableType, Type)
57285733

5734+
/// HoleType - This represents a placeholder type for a type variable
5735+
/// or dependent member type that cannot be resolved to a concrete type
5736+
/// because the expression is ambiguous. This type is only used by the
5737+
/// constraint solver and transformed into UnresolvedType to be used in AST.
5738+
class HoleType : public TypeBase {
5739+
using OriginatorType =
5740+
llvm::PointerUnion<TypeVariableType *, DependentMemberType *>;
5741+
5742+
OriginatorType Originator;
5743+
5744+
HoleType(ASTContext &C, OriginatorType originator,
5745+
RecursiveTypeProperties properties)
5746+
: TypeBase(TypeKind::Hole, &C, properties), Originator(originator) {}
5747+
5748+
public:
5749+
static Type get(ASTContext &ctx, OriginatorType originatorType);
5750+
5751+
OriginatorType getOriginatorType() const { return Originator; }
5752+
5753+
static bool classof(const TypeBase *T) {
5754+
return T->getKind() == TypeKind::Hole;
5755+
}
5756+
};
5757+
DEFINE_EMPTY_CAN_TYPE_WRAPPER(HoleType, Type)
5758+
57295759
inline bool TypeBase::isTypeVariableOrMember() {
57305760
if (is<TypeVariableType>())
57315761
return true;

lib/AST/ASTContext.cpp

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,8 +1466,9 @@ bool ASTContext::hadError() const {
14661466
/// Retrieve the arena from which we should allocate storage for a type.
14671467
static AllocationArena getArena(RecursiveTypeProperties properties) {
14681468
bool hasTypeVariable = properties.hasTypeVariable();
1469-
return hasTypeVariable? AllocationArena::ConstraintSolver
1470-
: AllocationArena::Permanent;
1469+
bool hasHole = properties.hasTypeHole();
1470+
return hasTypeVariable || hasHole ? AllocationArena::ConstraintSolver
1471+
: AllocationArena::Permanent;
14711472
}
14721473

14731474
void ASTContext::addSearchPath(StringRef searchPath, bool isFramework,
@@ -2358,6 +2359,17 @@ Type ErrorType::get(Type originalType) {
23582359
return entry = new (mem) ErrorType(ctx, originalType, properties);
23592360
}
23602361

2362+
Type HoleType::get(ASTContext &ctx, OriginatorType originator) {
2363+
assert(originator);
2364+
auto properties = reinterpret_cast<TypeBase *>(originator.getOpaqueValue())
2365+
->getRecursiveProperties();
2366+
properties |= RecursiveTypeProperties::HasTypeHole;
2367+
2368+
auto arena = getArena(properties);
2369+
return new (ctx, arena)
2370+
HoleType(ctx, originator, RecursiveTypeProperties::HasTypeHole);
2371+
}
2372+
23612373
BuiltinIntegerType *BuiltinIntegerType::get(BuiltinIntegerWidth BitWidth,
23622374
const ASTContext &C) {
23632375
assert(!BitWidth.isArbitraryWidth());
@@ -2799,6 +2811,7 @@ ReferenceStorageType *ReferenceStorageType::get(Type T,
27992811
ReferenceOwnership ownership,
28002812
const ASTContext &C) {
28012813
assert(!T->hasTypeVariable()); // not meaningful in type-checker
2814+
assert(!T->hasHole());
28022815
switch (optionalityOf(ownership)) {
28032816
case ReferenceOwnershipOptionality::Disallowed:
28042817
assert(!T->getOptionalObjectType() && "optional type is disallowed");
@@ -2957,7 +2970,7 @@ isFunctionTypeCanonical(ArrayRef<AnyFunctionType::Param> params,
29572970
static RecursiveTypeProperties
29582971
getGenericFunctionRecursiveProperties(ArrayRef<AnyFunctionType::Param> params,
29592972
Type result) {
2960-
static_assert(RecursiveTypeProperties::BitWidth == 11,
2973+
static_assert(RecursiveTypeProperties::BitWidth == 12,
29612974
"revisit this if you add new recursive type properties");
29622975
RecursiveTypeProperties properties;
29632976

@@ -3185,6 +3198,7 @@ GenericFunctionType *GenericFunctionType::get(GenericSignature sig,
31853198
ExtInfo info) {
31863199
assert(sig && "no generic signature for generic function type?!");
31873200
assert(!result->hasTypeVariable());
3201+
assert(!result->hasHole());
31883202

31893203
llvm::FoldingSetNodeID id;
31903204
GenericFunctionType::Profile(id, sig, params, result, info);
@@ -3509,7 +3523,7 @@ CanSILFunctionType SILFunctionType::get(
35093523
void *mem = ctx.Allocate(bytes, alignof(SILFunctionType));
35103524

35113525
RecursiveTypeProperties properties;
3512-
static_assert(RecursiveTypeProperties::BitWidth == 11,
3526+
static_assert(RecursiveTypeProperties::BitWidth == 12,
35133527
"revisit this if you add new recursive type properties");
35143528
for (auto &param : params)
35153529
properties |= param.getInterfaceType()->getRecursiveProperties();

lib/AST/ASTDumper.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3496,6 +3496,18 @@ namespace {
34963496

34973497
TRIVIAL_TYPE_PRINTER(Unresolved, unresolved)
34983498

3499+
void visitHoleType(HoleType *T, StringRef label) {
3500+
printCommon(label, "hole_type");
3501+
auto originatorTy = T->getOriginatorType();
3502+
if (auto *typeVar = originatorTy.dyn_cast<TypeVariableType *>()) {
3503+
printRec("type_variable", typeVar);
3504+
} else {
3505+
printRec("dependent_member_type",
3506+
originatorTy.get<DependentMemberType *>());
3507+
}
3508+
PrintWithColorRAII(OS, ParenthesisColor) << ')';
3509+
}
3510+
34993511
void visitBuiltinIntegerType(BuiltinIntegerType *T, StringRef label) {
35003512
printCommon(label, "builtin_integer_type");
35013513
if (T->isFixedWidth())

lib/AST/ASTMangler.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -923,6 +923,7 @@ void ASTMangler::appendType(Type type, const ValueDecl *forDecl) {
923923
TypeBase *tybase = type.getPointer();
924924
switch (type->getKind()) {
925925
case TypeKind::TypeVariable:
926+
case TypeKind::Hole:
926927
llvm_unreachable("mangling type variable");
927928

928929
case TypeKind::Module:

lib/AST/ASTPrinter.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3813,6 +3813,17 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
38133813
Printer << "_";
38143814
}
38153815

3816+
void visitHoleType(HoleType *T) {
3817+
if (Options.PrintTypesForDebugging) {
3818+
Printer << "<<hole for ";
3819+
auto originatorTy = T->getOriginatorType();
3820+
visit(Type(reinterpret_cast<TypeBase *>(originatorTy.getOpaqueValue())));
3821+
Printer << ">>";
3822+
} else {
3823+
Printer << "<<hole>>";
3824+
}
3825+
}
3826+
38163827
#ifdef ASTPRINTER_HANDLE_BUILTINTYPE
38173828
#error "ASTPRINTER_HANDLE_BUILTINTYPE should not be defined?!"
38183829
#endif

lib/AST/Expr.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ namespace {
126126
} // end anonymous namespace
127127

128128
void Expr::setType(Type T) {
129-
assert(!T || !T->hasTypeVariable());
129+
assert(!T || !T->hasTypeVariable() || !T->hasHole());
130130
Ty = T;
131131
}
132132

@@ -2001,7 +2001,7 @@ bool ClosureExpr::capturesSelfEnablingImplictSelf() const {
20012001
}
20022002

20032003
void ClosureExpr::setExplicitResultType(Type ty) {
2004-
assert(ty && !ty->hasTypeVariable());
2004+
assert(ty && !ty->hasTypeVariable() && !ty->hasHole());
20052005
ExplicitResultTypeAndBodyState.getPointer()
20062006
->setType(MetatypeType::get(ty));
20072007
}

lib/AST/SILLayout.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ static void verifyFields(CanGenericSignature Sig, ArrayRef<SILField> Fields) {
5252
&& "SILLayout field cannot have an archetype type");
5353
assert(!ty->hasTypeVariable()
5454
&& "SILLayout cannot contain constraint system type variables");
55+
assert(!ty->hasHole() &&
56+
"SILLayout cannot contain constraint system type holes");
5557
if (!ty->hasTypeParameter())
5658
continue;
5759
field.getLoweredType().findIf([Sig](Type t) -> bool {

lib/AST/Type.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ Type QuerySubstitutionMap::operator()(SubstitutableType *type) const {
7676
}
7777

7878
void TypeLoc::setType(Type Ty) {
79-
assert(!Ty || !Ty->hasTypeVariable());
79+
assert(!Ty || !Ty->hasTypeVariable() || !Ty->hasHole());
8080
this->Ty = Ty;
8181
}
8282

@@ -153,9 +153,7 @@ bool TypeBase::isAny() {
153153
return isEqual(getASTContext().TheAnyType);
154154
}
155155

156-
bool TypeBase::isHole() {
157-
return isEqual(getASTContext().TheUnresolvedType);
158-
}
156+
bool TypeBase::isHole() { return getCanonicalType()->is<HoleType>(); }
159157

160158
bool TypeBase::isAnyClassReferenceType() {
161159
return getCanonicalType().isAnyClassReferenceType();
@@ -221,6 +219,7 @@ bool CanType::isReferenceTypeImpl(CanType type, const GenericSignatureImpl *sig,
221219
case TypeKind::LValue:
222220
case TypeKind::InOut:
223221
case TypeKind::TypeVariable:
222+
case TypeKind::Hole:
224223
case TypeKind::BoundGenericEnum:
225224
case TypeKind::BoundGenericStruct:
226225
case TypeKind::SILToken:
@@ -1149,6 +1148,7 @@ CanType TypeBase::computeCanonicalType() {
11491148
case TypeKind::Error:
11501149
case TypeKind::Unresolved:
11511150
case TypeKind::TypeVariable:
1151+
case TypeKind::Hole:
11521152
llvm_unreachable("these types are always canonical");
11531153

11541154
#define SUGARED_TYPE(id, parent) \
@@ -4244,6 +4244,7 @@ case TypeKind::Id:
42444244
case TypeKind::Error:
42454245
case TypeKind::Unresolved:
42464246
case TypeKind::TypeVariable:
4247+
case TypeKind::Hole:
42474248
case TypeKind::GenericTypeParam:
42484249
case TypeKind::SILToken:
42494250
case TypeKind::Module:
@@ -4982,6 +4983,7 @@ ReferenceCounting TypeBase::getReferenceCounting() {
49824983
case TypeKind::LValue:
49834984
case TypeKind::InOut:
49844985
case TypeKind::TypeVariable:
4986+
case TypeKind::Hole:
49854987
case TypeKind::BoundGenericEnum:
49864988
case TypeKind::BoundGenericStruct:
49874989
case TypeKind::SILToken:

lib/AST/TypeCheckRequests.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,7 @@ void InterfaceTypeRequest::cacheResult(Type type) const {
10131013
auto *decl = std::get<0>(getStorage());
10141014
if (type) {
10151015
assert(!type->hasTypeVariable() && "Type variable in interface type");
1016+
assert(!type->hasHole() && "Type hole in interface type");
10161017
assert(!type->is<InOutType>() && "Interface type must be materializable");
10171018
assert(!type->hasArchetype() && "Archetype in interface type");
10181019
}

lib/AST/TypeJoinMeet.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ struct TypeJoin : CanTypeVisitor<TypeJoin, CanType> {
8787
assert(!first->hasTypeVariable() && !second->hasTypeVariable() &&
8888
"Cannot compute join of types involving type variables");
8989

90+
assert(!first->hasHole() && !second->hasHole() &&
91+
"Cannot compute join of types involving type holes");
92+
9093
assert(first->getWithoutSpecifierType()->isEqual(first) &&
9194
"Expected simple type!");
9295
assert(second->getWithoutSpecifierType()->isEqual(second) &&

lib/AST/TypeWalker.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class Traversal : public TypeVisitor<Traversal, bool>
3434

3535
bool visitErrorType(ErrorType *ty) { return false; }
3636
bool visitUnresolvedType(UnresolvedType *ty) { return false; }
37+
bool visitHoleType(HoleType *ty) { return false; }
3738
bool visitBuiltinType(BuiltinType *ty) { return false; }
3839
bool visitTypeAliasType(TypeAliasType *ty) {
3940
if (auto parent = ty->getParent())

lib/IRGen/IRGenDebugInfo.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1571,6 +1571,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
15711571
case TypeKind::Unresolved:
15721572
case TypeKind::LValue:
15731573
case TypeKind::TypeVariable:
1574+
case TypeKind::Hole:
15741575
case TypeKind::Module:
15751576
case TypeKind::SILBlockStorage:
15761577
case TypeKind::SILBox:

lib/Sema/CSApply.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7674,6 +7674,8 @@ namespace {
76747674
// "Mismatched types!");
76757675
assert(!exprType->hasTypeVariable() &&
76767676
"Should not write type variable into expression!");
7677+
assert(!exprType->hasHole() &&
7678+
"Should not write type holes into expression!");
76777679
expr->setType(exprType);
76787680

76797681
if (auto kp = dyn_cast<KeyPathExpr>(expr)) {
@@ -7683,6 +7685,8 @@ namespace {
76837685
componentType = solution.simplifyType(cs.getType(kp, i));
76847686
assert(!componentType->hasTypeVariable() &&
76857687
"Should not write type variable into key-path component");
7688+
assert(!componentType->hasHole() &&
7689+
"Should not write type hole into key-path component");
76867690
kp->getMutableComponents()[i].setComponentType(componentType);
76877691
}
76887692
}

lib/Sema/CSBindings.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ void ConstraintSystem::PotentialBindings::finalize(
335335
if (locator->isLastElement<LocatorPathElt::MemberRefBase>())
336336
PotentiallyIncomplete = true;
337337

338-
addPotentialBinding(PotentialBinding::forHole(cs.getASTContext(), locator));
338+
addPotentialBinding(PotentialBinding::forHole(TypeVar, locator));
339339
}
340340

341341
// Let's always consider `Any` to be a last resort binding because
@@ -481,6 +481,7 @@ void ConstraintSystem::PotentialBindings::addPotentialBinding(
481481
if (binding.Kind == AllowedBindingKind::Supertypes &&
482482
!binding.BindingType->hasUnresolvedType() &&
483483
!binding.BindingType->hasTypeVariable() &&
484+
!binding.BindingType->hasHole() &&
484485
!binding.BindingType->hasUnboundGenericType() &&
485486
!binding.hasDefaultedLiteralProtocol() &&
486487
!binding.isDefaultableBinding() && allowJoinMeet) {

lib/Sema/CSDiagnostics.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,8 +1247,10 @@ bool MissingOptionalUnwrapFailure::diagnoseAsError() {
12471247

12481248
assert(!baseType->hasTypeVariable() &&
12491249
"Base type must not be a type variable");
1250+
assert(!baseType->isHole() && "Base type must not be a type hole");
12501251
assert(!unwrappedType->hasTypeVariable() &&
12511252
"Unwrapped type must not be a type variable");
1253+
assert(!unwrappedType->isHole() && "Unwrapped type must not be a type hole");
12521254

12531255
if (!baseType->getOptionalObjectType())
12541256
return false;
@@ -5098,7 +5100,7 @@ bool CollectionElementContextualFailure::diagnoseAsError() {
50985100
// holes present in the contextual type.
50995101
if (FailureDiagnostic::getContextualTypePurpose(getAnchor()) ==
51005102
ContextualTypePurpose::CTP_ForEachStmt &&
5101-
contextualType->hasHole()) {
5103+
contextualType->hasUnresolvedType()) {
51025104
diagnostic.emplace(emitDiagnostic(
51035105
(contextualType->is<TupleType>() && !eltType->is<TupleType>())
51045106
? diag::cannot_match_expr_tuple_pattern_with_nontuple_value
@@ -6356,7 +6358,7 @@ bool UnableToInferClosureParameterType::diagnoseAsError() {
63566358
if (parentExpr) {
63576359
// Missing or invalid member reference in call.
63586360
if (auto *AE = dyn_cast<ApplyExpr>(parentExpr)) {
6359-
if (getType(AE->getFn())->isHole())
6361+
if (getType(AE->getFn())->is<UnresolvedType>())
63606362
return false;
63616363
}
63626364

lib/Sema/CSDiagnostics.h

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -94,20 +94,26 @@ class FailureDiagnostic {
9494
/// Resolve type variables present in the raw type, if any.
9595
Type resolveType(Type rawType, bool reconstituteSugar = false,
9696
bool wantRValue = true) const {
97-
if (!rawType->hasTypeVariable()) {
98-
if (reconstituteSugar)
99-
rawType = rawType->reconstituteSugar(/*recursive*/ true);
100-
return wantRValue ? rawType->getRValueType() : rawType;
97+
auto &cs = getConstraintSystem();
98+
99+
if (rawType->hasTypeVariable() || rawType->hasHole()) {
100+
rawType = rawType.transform([&](Type type) {
101+
if (auto *typeVar = type->getAs<TypeVariableType>()) {
102+
auto resolvedType = S.simplifyType(typeVar);
103+
Type GP = typeVar->getImpl().getGenericParameter();
104+
return resolvedType->is<UnresolvedType>() && GP
105+
? GP
106+
: resolvedType;
107+
}
108+
109+
return type->isHole() ? Type(cs.getASTContext().TheUnresolvedType)
110+
: type;
111+
});
101112
}
102113

103-
auto &cs = getConstraintSystem();
104-
return cs.simplifyTypeImpl(rawType, [&](TypeVariableType *typeVar) -> Type {
105-
auto fixed = S.simplifyType(typeVar);
106-
auto *genericParam = typeVar->getImpl().getGenericParameter();
107-
if (fixed->isHole() && genericParam)
108-
return genericParam;
109-
return resolveType(fixed, reconstituteSugar, wantRValue);
110-
});
114+
if (reconstituteSugar)
115+
rawType = rawType->reconstituteSugar(/*recursive*/ true);
116+
return wantRValue ? rawType->getRValueType() : rawType;
111117
}
112118

113119
template <typename... ArgTypes>

0 commit comments

Comments
 (0)