Skip to content

Commit 2133fe2

Browse files
committed
Sema: Have TypeResolution accept an unbound generic type opener function
1 parent 1f40d2a commit 2133fe2

16 files changed

+376
-221
lines changed

include/swift/AST/TypeCheckRequests.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2444,7 +2444,7 @@ class HasImplementationOnlyImportsRequest
24442444

24452445
class ResolveTypeRequest
24462446
: public SimpleRequest<ResolveTypeRequest,
2447-
Type(TypeResolution *, TypeRepr *),
2447+
Type(const TypeResolution *, TypeRepr *),
24482448
RequestFlags::Uncached> {
24492449
public:
24502450
using SimpleRequest::SimpleRequest;
@@ -2457,7 +2457,7 @@ class ResolveTypeRequest
24572457
friend SimpleRequest;
24582458

24592459
// Evaluation.
2460-
Type evaluate(Evaluator &evaluator, TypeResolution *resolution,
2460+
Type evaluate(Evaluator &evaluator, const TypeResolution *resolution,
24612461
TypeRepr *repr) const;
24622462
};
24632463

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,8 @@ SWIFT_REQUEST(TypeChecker, ResolveTypeEraserTypeRequest,
240240
Type(ProtocolDecl *, TypeEraserAttr *),
241241
SeparatelyCached, NoLocationInfo)
242242
SWIFT_REQUEST(TypeChecker, ResolveTypeRequest,
243-
Type (TypeResolution *, TypeRepr *), Uncached, NoLocationInfo)
243+
Type (const TypeResolution *, TypeRepr *),
244+
Uncached, NoLocationInfo)
244245
SWIFT_REQUEST(TypeChecker, SPIGroupsRequest,
245246
llvm::ArrayRef<Identifier>(Decl *),
246247
Cached, NoLocationInfo)

lib/Sema/CSGen.cpp

Lines changed: 81 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1445,12 +1445,19 @@ namespace {
14451445
diag::super_with_no_base_class);
14461446
}
14471447

1448-
Type resolveTypeReferenceInExpression(TypeRepr *repr,
1449-
TypeResolverContext resCtx) {
1450-
TypeResolutionOptions options(resCtx);
1451-
options |= TypeResolutionFlags::AllowUnboundGenerics;
1452-
auto result = TypeResolution::forContextual(CS.DC, options)
1453-
.resolveType(repr);
1448+
Type
1449+
resolveTypeReferenceInExpression(TypeRepr *repr, TypeResolverContext resCtx,
1450+
OpenUnboundGenericTypeFn unboundTyOpener) {
1451+
if (!unboundTyOpener) {
1452+
unboundTyOpener = [](auto unboundTy) {
1453+
// FIXME: Don't let unbound generic types escape type resolution.
1454+
// For now, just return the unbound generic type.
1455+
return unboundTy;
1456+
};
1457+
}
1458+
const auto result =
1459+
TypeResolution::forContextual(CS.DC, resCtx, unboundTyOpener)
1460+
.resolveType(repr);
14541461
if (result->hasError()) {
14551462
return Type();
14561463
}
@@ -1460,20 +1467,21 @@ namespace {
14601467
Type visitTypeExpr(TypeExpr *E) {
14611468
Type type;
14621469
// If this is an implicit TypeExpr, don't validate its contents.
1470+
auto *const locator = CS.getConstraintLocator(E);
14631471
if (E->isImplicit()) {
14641472
type = CS.getInstanceType(CS.cacheType(E));
14651473
assert(type && "Implicit type expr must have type set!");
1474+
type = CS.openUnboundGenericTypes(type, locator);
14661475
} else {
14671476
auto *repr = E->getTypeRepr();
14681477
assert(repr && "Explicit node has no type repr!");
14691478
type = resolveTypeReferenceInExpression(
1470-
repr, TypeResolverContext::InExpression);
1479+
repr, TypeResolverContext::InExpression,
1480+
OpenUnboundGenericType(CS, locator));
14711481
}
14721482

14731483
if (!type || type->hasError()) return Type();
1474-
1475-
auto locator = CS.getConstraintLocator(E);
1476-
type = CS.openUnboundGenericTypes(type, locator);
1484+
14771485
return MetatypeType::get(type);
14781486
}
14791487

@@ -1711,12 +1719,15 @@ namespace {
17111719

17121720
// Bind the specified generic arguments to the type variables in the
17131721
// open type.
1714-
auto locator = CS.getConstraintLocator(expr);
1722+
auto *const locator = CS.getConstraintLocator(expr);
1723+
const auto options =
1724+
TypeResolutionOptions(TypeResolverContext::InExpression);
17151725
for (size_t i = 0, size = specializations.size(); i < size; ++i) {
1716-
TypeResolutionOptions options(TypeResolverContext::InExpression);
1717-
options |= TypeResolutionFlags::AllowUnboundGenerics;
1718-
auto result = TypeResolution::forContextual(CS.DC, options)
1719-
.resolveType(specializations[i]);
1726+
const auto resolution = TypeResolution::forContextual(
1727+
CS.DC, options,
1728+
// Introduce type variables for unbound generics.
1729+
OpenUnboundGenericType(CS, locator));
1730+
const auto result = resolution.resolveType(specializations[i]);
17201731
if (result->hasError())
17211732
return Type();
17221733

@@ -2190,7 +2201,7 @@ namespace {
21902201

21912202
return resolveTypeReferenceInExpression(
21922203
closure->getExplicitResultTypeRepr(),
2193-
TypeResolverContext::InExpression);
2204+
TypeResolverContext::InExpression, nullptr);
21942205
};
21952206

21962207
Type resultTy;
@@ -2493,17 +2504,12 @@ namespace {
24932504
case PatternKind::Is: {
24942505
auto isPattern = cast<IsPattern>(pattern);
24952506

2496-
Type castType = resolveTypeReferenceInExpression(
2497-
isPattern->getCastTypeRepr(), TypeResolverContext::InExpression);
2498-
2499-
if (!castType)
2500-
return Type();
2501-
2502-
castType = CS.openUnboundGenericTypes(
2503-
castType,
2504-
locator.withPathElement(LocatorPathElt::PatternMatch(pattern)));
2505-
2506-
assert(castType);
2507+
const Type castType = resolveTypeReferenceInExpression(
2508+
isPattern->getCastTypeRepr(), TypeResolverContext::InExpression,
2509+
OpenUnboundGenericType(CS,
2510+
locator.withPathElement(
2511+
LocatorPathElt::PatternMatch(pattern))));
2512+
if (!castType) return Type();
25072513

25082514
auto *subPattern = isPattern->getSubPattern();
25092515
Type subPatternType = getTypeForPattern(
@@ -2559,7 +2565,14 @@ namespace {
25592565
}
25602566
return resolveTypeReferenceInExpression(
25612567
enumPattern->getParentTypeRepr(),
2562-
TypeResolverContext::InExpression);
2568+
TypeResolverContext::InExpression, [](auto unboundTy) {
2569+
// FIXME: We ought to pass an OpenUnboundGenericType object
2570+
// rather than calling CS.openUnboundGenericType below, but
2571+
// sometimes the parent type is resolved eagerly in
2572+
// ResolvePattern::visitUnresolvedDotExpr, letting unbound
2573+
// generics escape.
2574+
return unboundTy;
2575+
});
25632576
}();
25642577

25652578
if (!parentType)
@@ -2725,9 +2738,10 @@ namespace {
27252738
// of is-patterns applied to an irrefutable pattern.
27262739
pattern = pattern->getSemanticsProvidingPattern();
27272740
while (auto isp = dyn_cast<IsPattern>(pattern)) {
2728-
Type castType = TypeResolution::forContextual(
2729-
CS.DC, TypeResolverContext::InExpression)
2730-
.resolveType(isp->getCastTypeRepr());
2741+
const Type castType = TypeResolution::forContextual(
2742+
CS.DC, TypeResolverContext::InExpression,
2743+
/*unboundTyOpener*/ nullptr)
2744+
.resolveType(isp->getCastTypeRepr());
27312745
if (castType->hasError()) {
27322746
return false;
27332747
}
@@ -3051,14 +3065,14 @@ namespace {
30513065

30523066
auto *const repr = expr->getCastTypeRepr();
30533067
// Validate the resulting type.
3054-
const auto type = resolveTypeReferenceInExpression(
3055-
repr, TypeResolverContext::ExplicitCastExpr);
3056-
if (!type)
3068+
const auto toType = resolveTypeReferenceInExpression(
3069+
repr, TypeResolverContext::ExplicitCastExpr,
3070+
// Introduce type variables for unbound generics.
3071+
OpenUnboundGenericType(CS, CS.getConstraintLocator(expr)));
3072+
if (!toType)
30573073
return nullptr;
30583074

3059-
// Open the type we're casting to.
3060-
const auto toType =
3061-
CS.openUnboundGenericTypes(type, CS.getConstraintLocator(expr));
3075+
// Cache the type we're casting to.
30623076
if (repr) CS.setType(repr, toType);
30633077

30643078
auto fromType = CS.getType(fromExpr);
@@ -3079,7 +3093,14 @@ namespace {
30793093
// Validate the resulting type.
30803094
auto *const repr = expr->getCastTypeRepr();
30813095
const auto type = resolveTypeReferenceInExpression(
3082-
repr, TypeResolverContext::ExplicitCastExpr);
3096+
repr, TypeResolverContext::ExplicitCastExpr, [](auto unboundTy) {
3097+
// FIXME: We ought to pass an OpenUnboundGenericType object rather
3098+
// than calling CS.openUnboundGenericType after resolving, but
3099+
// sometimes the type expression is resolved eagerly in
3100+
// PreCheckExpression::simplifyTypeConstructionWithLiteralArg,
3101+
// letting unbound generics escape.
3102+
return unboundTy;
3103+
});
30833104
if (!type)
30843105
return nullptr;
30853106

@@ -3111,14 +3132,14 @@ namespace {
31113132

31123133
// Validate the resulting type.
31133134
auto *const repr = expr->getCastTypeRepr();
3114-
const auto type = resolveTypeReferenceInExpression(
3115-
repr, TypeResolverContext::ExplicitCastExpr);
3116-
if (!type)
3135+
const auto toType = resolveTypeReferenceInExpression(
3136+
repr, TypeResolverContext::ExplicitCastExpr,
3137+
// Introduce type variables for unbound generics.
3138+
OpenUnboundGenericType(CS, CS.getConstraintLocator(expr)));
3139+
if (!toType)
31173140
return nullptr;
31183141

3119-
// Open the type we're casting to.
3120-
const auto toType =
3121-
CS.openUnboundGenericTypes(type, CS.getConstraintLocator(expr));
3142+
// Cache the type we're casting to.
31223143
if (repr) CS.setType(repr, toType);
31233144

31243145
auto fromType = CS.getType(fromExpr);
@@ -3137,17 +3158,16 @@ namespace {
31373158

31383159
Type visitIsExpr(IsExpr *expr) {
31393160
// Validate the type.
3161+
// FIXME: Locator for the cast type?
31403162
auto &ctx = CS.getASTContext();
3141-
const auto type = resolveTypeReferenceInExpression(
3142-
expr->getCastTypeRepr(),
3143-
TypeResolverContext::ExplicitCastExpr);
3144-
if (!type)
3163+
const auto toType = resolveTypeReferenceInExpression(
3164+
expr->getCastTypeRepr(), TypeResolverContext::ExplicitCastExpr,
3165+
// Introduce type variables for unbound generics.
3166+
OpenUnboundGenericType(CS, CS.getConstraintLocator(expr)));
3167+
if (!toType)
31453168
return nullptr;
31463169

3147-
// Open up the type we're checking.
3148-
// FIXME: Locator for the cast type?
3149-
const auto toType =
3150-
CS.openUnboundGenericTypes(type, CS.getConstraintLocator(expr));
3170+
// Cache the type we're checking.
31513171
CS.setType(expr->getCastTypeRepr(), toType);
31523172

31533173
// Add a checked cast constraint.
@@ -3353,7 +3373,7 @@ namespace {
33533373
// Just resolve the referenced type.
33543374
// FIXME: The type reference needs to be opened into context.
33553375
return resolveTypeReferenceInExpression(
3356-
placeholderRepr, TypeResolverContext::InExpression);
3376+
placeholderRepr, TypeResolverContext::InExpression, nullptr);
33573377
}
33583378

33593379
auto locator = CS.getConstraintLocator(E);
@@ -3423,11 +3443,13 @@ namespace {
34233443

34243444
// If a root type was explicitly given, then resolve it now.
34253445
if (auto rootRepr = E->getRootType()) {
3426-
auto rootObjectTy = resolveTypeReferenceInExpression(
3427-
rootRepr, TypeResolverContext::InExpression);
3446+
const auto rootObjectTy = resolveTypeReferenceInExpression(
3447+
rootRepr, TypeResolverContext::InExpression,
3448+
// Introduce type variables for unbound generics.
3449+
OpenUnboundGenericType(CS, locator));
34283450
if (!rootObjectTy || rootObjectTy->hasError())
34293451
return Type();
3430-
rootObjectTy = CS.openUnboundGenericTypes(rootObjectTy, locator);
3452+
34313453
// Allow \Derived.property to be inferred as \Base.property to
34323454
// simulate a sort of covariant conversion from
34333455
// KeyPath<Derived, T> to KeyPath<Base, T>.
@@ -3887,6 +3909,9 @@ static Type generateWrappedPropertyTypeConstraints(
38873909

38883910
auto wrapperAttributes = wrappedVar->getAttachedPropertyWrappers();
38893911
for (unsigned i : indices(wrapperAttributes)) {
3912+
// FIXME: We should somehow pass an OpenUnboundGenericTypeFn to
3913+
// AttachedPropertyWrapperTypeRequest::evaluate to open up unbound
3914+
// generics on the fly.
38903915
Type rawWrapperType = wrappedVar->getAttachedPropertyWrapperType(i);
38913916
auto wrapperInfo = wrappedVar->getAttachedPropertyWrapperTypeInfo(i);
38923917
if (rawWrapperType->hasError() || !wrapperInfo)

lib/Sema/CSSolver.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -997,8 +997,14 @@ void ConstraintSystem::shrink(Expr *expr) {
997997
auto *const typeRepr = coerceExpr->getCastTypeRepr();
998998

999999
if (typeRepr && isSuitableCollection(typeRepr)) {
1000-
auto resolution = TypeResolution::forContextual(CS.DC, None);
1001-
auto coercionType = resolution.resolveType(typeRepr);
1000+
const auto coercionType =
1001+
TypeResolution::forContextual(
1002+
CS.DC, None,
1003+
// FIXME: Should we really be unconditionally complaining
1004+
// about unbound generics here? For example:
1005+
// let foo: [Array<Float>] = [[0], [1], [2]] as [Array]
1006+
/*unboundTyOpener*/ nullptr)
1007+
.resolveType(typeRepr);
10021008

10031009
// Looks like coercion type is invalid, let's skip this sub-tree.
10041010
if (coercionType->hasError())

lib/Sema/ConstraintSystem.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,8 @@ Type ConstraintSystem::openUnboundGenericType(
698698
// handle generic TypeAliases elsewhere, this can just become a
699699
// call to BoundGenericType::get().
700700
return TypeChecker::applyUnboundGenericArguments(
701-
decl, parentTy, SourceLoc(), TypeResolution::forContextual(DC, None),
701+
decl, parentTy, SourceLoc(),
702+
TypeResolution::forContextual(DC, None, /*unboundTyOpener*/ nullptr),
702703
arguments);
703704
}
704705

@@ -1217,7 +1218,8 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value,
12171218
// Resolve the reference to this type declaration in our current context.
12181219
auto type = TypeChecker::resolveTypeInContext(
12191220
typeDecl, nullptr,
1220-
TypeResolution::forContextual(useDC, TypeResolverContext::InExpression),
1221+
TypeResolution::forContextual(useDC, TypeResolverContext::InExpression,
1222+
/*unboundTyOpener*/ nullptr),
12211223
/*isSpecialized=*/false);
12221224

12231225
checkNestedTypeConstraints(*this, type, locator);

lib/Sema/ConstraintSystem.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5027,6 +5027,25 @@ class ConstraintSystem {
50275027
void print(raw_ostream &out, Expr *) const;
50285028
};
50295029

5030+
/// A function object suitable for use as an \c OpenUnboundGenericTypeFn that
5031+
/// "opens" the given unbound type by introducing fresh type variables for
5032+
/// generic parameters and constructing a bound generic type from these
5033+
/// type variables.
5034+
class OpenUnboundGenericType {
5035+
ConstraintSystem &cs;
5036+
const ConstraintLocatorBuilder &locator;
5037+
5038+
public:
5039+
explicit OpenUnboundGenericType(ConstraintSystem &cs,
5040+
const ConstraintLocatorBuilder &locator)
5041+
: cs(cs), locator(locator) {}
5042+
5043+
Type operator()(UnboundGenericType *unboundTy) const {
5044+
return cs.openUnboundGenericType(unboundTy->getDecl(),
5045+
unboundTy->getParent(), locator);
5046+
}
5047+
};
5048+
50305049
/// Compute the shuffle required to map from a given tuple type to
50315050
/// another tuple type.
50325051
///

0 commit comments

Comments
 (0)