Skip to content

Commit 2e0be5a

Browse files
committed
[CS] Open generic requirements for types with unbound + placeholder types
- Introduce a generic requirements opening function for type resolution, which is used by the constraint system in cases where we need to impose requirements on opened type variables. - Refactor `replaceInferableTypesWithTypeVars` to use this function when opening generic types that contain either placeholder or unbound generic types. Together these changes ensure that we don't drop generic requirements when an unbound generic or placeholder type is used as a generic argument.
1 parent 52bb8b4 commit 2e0be5a

File tree

9 files changed

+322
-122
lines changed

9 files changed

+322
-122
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5796,6 +5796,23 @@ class OpenUnboundGenericType {
57965796
}
57975797
};
57985798

5799+
/// A function object suitable for use as an \c OpenRequirementFn that "opens"
5800+
/// the requirements for a given type's generic signature given a set of
5801+
/// argument substitutions.
5802+
class OpenGenericTypeRequirements {
5803+
ConstraintSystem &cs;
5804+
const ConstraintLocatorBuilder &locator;
5805+
PreparedOverloadBuilder *preparedOverload;
5806+
5807+
public:
5808+
explicit OpenGenericTypeRequirements(
5809+
ConstraintSystem &cs, const ConstraintLocatorBuilder &locator,
5810+
PreparedOverloadBuilder *preparedOverload)
5811+
: cs(cs), locator(locator), preparedOverload(preparedOverload) {}
5812+
5813+
void operator()(GenericTypeDecl *decl, TypeSubstitutionFn subst) const;
5814+
};
5815+
57995816
class HandlePlaceholderType {
58005817
ConstraintSystem &cs;
58015818
ConstraintLocator *locator;

lib/Sema/CSGen.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1697,6 +1697,9 @@ namespace {
16971697
// Introduce type variables for unbound generics.
16981698
const auto genericOpener = OpenUnboundGenericType(CS, locator);
16991699
const auto placeholderHandler = HandlePlaceholderType(CS, locator);
1700+
const auto requirementOpener =
1701+
OpenGenericTypeRequirements(CS, locator,
1702+
/*preparedOverload*/ nullptr);
17001703

17011704
// Add a PackElementOf constraint for 'each T' type reprs.
17021705
PackExpansionExpr *elementEnv = nullptr;
@@ -1708,7 +1711,7 @@ namespace {
17081711

17091712
const auto result = TypeResolution::resolveContextualType(
17101713
repr, CS.DC, options, genericOpener, placeholderHandler,
1711-
packElementOpener);
1714+
packElementOpener, requirementOpener);
17121715
if (result->hasError()) {
17131716
CS.recordFix(
17141717
IgnoreInvalidASTNode::create(CS, CS.getConstraintLocator(locator)));
@@ -1973,7 +1976,9 @@ namespace {
19731976
// Introduce type variables for unbound generics.
19741977
OpenUnboundGenericType(CS, argLocator),
19751978
HandlePlaceholderType(CS, argLocator),
1976-
OpenPackElementType(CS, argLocator, elementEnv));
1979+
OpenPackElementType(CS, argLocator, elementEnv),
1980+
OpenGenericTypeRequirements(CS, locator,
1981+
/*preparedOverload*/ nullptr));
19771982
if (result->hasError()) {
19781983
auto &ctxt = CS.getASTContext();
19791984
result = PlaceholderType::get(ctxt, specializationArg);

lib/Sema/ConstraintSystem.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3414,6 +3414,39 @@ bool ConstraintSystem::diagnoseAmbiguity(ArrayRef<Solution> solutions) {
34143414
return false;
34153415
}
34163416

3417+
void OpenGenericTypeRequirements::operator()(GenericTypeDecl *decl,
3418+
TypeSubstitutionFn subst) const {
3419+
auto *outerDC = decl->getDeclContext();
3420+
auto sig = decl->getGenericSignature();
3421+
3422+
// In principle we shouldn't need to open the generic parameters here, we
3423+
// could just open the requirements using the substituted arguments directly,
3424+
// but that doesn't allow us to correctly handle requirement fix coalescing
3425+
// in `isFixedRequirement`. So instead we open the generic parameters and
3426+
// then bind the resulting type variables to the substituted args.
3427+
SmallVector<OpenedType, 4> replacements;
3428+
cs.openGenericParameters(outerDC, sig, replacements, locator,
3429+
preparedOverload);
3430+
3431+
// FIXME: Get rid of fixmeAllowDuplicates. This is the same issue as in
3432+
// `openUnboundGenericType`; both `applyUnboundGenericArguments` &
3433+
// `replaceInferableTypesWithTypeVars` can open multiple different generic
3434+
// types with the same locator. For the former we ought to plumb through the
3435+
// TypeRepr and use that to distinguish the locator. For the latter we ought
3436+
// to try migrating clients off it, pushing the opening up to type resolution.
3437+
cs.recordOpenedTypes(locator, replacements, preparedOverload,
3438+
/*fixmeAllowDuplicates*/ true);
3439+
3440+
for (auto [gp, typeVar] : replacements)
3441+
cs.addConstraint(ConstraintKind::Bind, typeVar, subst(gp), locator);
3442+
3443+
auto openType = [&](Type ty) -> Type {
3444+
return cs.openType(ty, replacements, locator, preparedOverload);
3445+
};
3446+
cs.openGenericRequirements(outerDC, sig, /*skipProtocolSelf*/ false, locator,
3447+
openType, preparedOverload);
3448+
}
3449+
34173450
ConstraintLocator *
34183451
constraints::simplifyLocator(ConstraintSystem &cs, ConstraintLocator *locator,
34193452
SourceRange &range) {

lib/Sema/TypeCheckType.cpp

Lines changed: 77 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -77,36 +77,40 @@ TypeResolution::forStructural(DeclContext *dc, TypeResolutionOptions options,
7777
HandlePlaceholderTypeReprFn placeholderHandler,
7878
OpenPackElementFn packElementOpener) {
7979
return TypeResolution(dc, {}, TypeResolutionStage::Structural, options,
80-
unboundTyOpener, placeholderHandler, packElementOpener);
80+
unboundTyOpener, placeholderHandler, packElementOpener,
81+
/*requirementOpener*/ nullptr);
8182
}
8283

8384
TypeResolution
8485
TypeResolution::forInterface(DeclContext *dc, TypeResolutionOptions options,
8586
OpenUnboundGenericTypeFn unboundTyOpener,
8687
HandlePlaceholderTypeReprFn placeholderHandler,
87-
OpenPackElementFn packElementOpener) {
88+
OpenPackElementFn packElementOpener,
89+
OpenRequirementFn requirementOpener) {
8890
return forInterface(dc, dc->getGenericSignatureOfContext(), options,
89-
unboundTyOpener, placeholderHandler, packElementOpener);
91+
unboundTyOpener, placeholderHandler, packElementOpener,
92+
requirementOpener);
9093
}
9194

92-
TypeResolution
93-
TypeResolution::forInterface(DeclContext *dc, GenericSignature genericSig,
94-
TypeResolutionOptions options,
95-
OpenUnboundGenericTypeFn unboundTyOpener,
96-
HandlePlaceholderTypeReprFn placeholderHandler,
97-
OpenPackElementFn packElementOpener) {
95+
TypeResolution TypeResolution::forInterface(
96+
DeclContext *dc, GenericSignature genericSig, TypeResolutionOptions options,
97+
OpenUnboundGenericTypeFn unboundTyOpener,
98+
HandlePlaceholderTypeReprFn placeholderHandler,
99+
OpenPackElementFn packElementOpener, OpenRequirementFn requirementOpener) {
98100
return TypeResolution(dc, genericSig, TypeResolutionStage::Interface, options,
99-
unboundTyOpener, placeholderHandler, packElementOpener);
101+
unboundTyOpener, placeholderHandler, packElementOpener,
102+
requirementOpener);
100103
}
101104

102105
TypeResolution TypeResolution::withOptions(TypeResolutionOptions opts) const {
103106
return TypeResolution(dc, genericSig, stage, opts, unboundTyOpener,
104-
placeholderHandler, packElementOpener);
107+
placeholderHandler, packElementOpener,
108+
requirementOpener);
105109
}
106110

107111
TypeResolution TypeResolution::withoutPackElementOpener() const {
108112
return TypeResolution(dc, genericSig, stage, options, unboundTyOpener,
109-
placeholderHandler, {});
113+
placeholderHandler, {}, requirementOpener);
110114
}
111115

112116
ASTContext &TypeResolution::getASTContext() const {
@@ -1185,6 +1189,7 @@ Type TypeResolution::applyUnboundGenericArguments(
11851189
// or unbound generics, let's skip the check here, and let the solver
11861190
// do it when missing types are deduced.
11871191
bool skipRequirementsCheck = false;
1192+
bool hasTypeVariables = false;
11881193
if (options.contains(TypeResolutionFlags::SILType)) {
11891194
if (auto nominal = dyn_cast<NominalTypeDecl>(decl)) {
11901195
if (nominal->isOptionalDecl()) {
@@ -1215,7 +1220,7 @@ Type TypeResolution::applyUnboundGenericArguments(
12151220
subs = parentTy->getContextSubstitutions(decl->getDeclContext());
12161221
}
12171222

1218-
skipRequirementsCheck |= parentTy->hasTypeVariable();
1223+
hasTypeVariables |= parentTy->hasTypeVariable();
12191224

12201225
// Fill in substitutions for outer generic parameters if we have a local
12211226
// type in generic context. This isn't actually supported all the way,
@@ -1243,56 +1248,59 @@ Type TypeResolution::applyUnboundGenericArguments(
12431248
// Enter the substitution.
12441249
subs[paramTy] = substTy;
12451250

1246-
skipRequirementsCheck |=
1247-
substTy->hasTypeVariable() || substTy->hasUnboundGenericType();
1251+
hasTypeVariables |= substTy->hasTypeVariable();
1252+
skipRequirementsCheck |= substTy->hasUnboundGenericType();
12481253
}
12491254

1255+
const auto substitutions = [&](SubstitutableType *type) -> Type {
1256+
auto result = QueryTypeSubstitutionMap{subs}(type);
1257+
if (result->hasTypeParameter()) {
1258+
if (const auto contextSig = getGenericSignature()) {
1259+
auto *genericEnv = contextSig.getGenericEnvironment();
1260+
// FIXME: This should just use mapTypeIntoContext(), but we can't yet
1261+
// because we sometimes have type parameters here that are invalid for
1262+
// our generic signature. This can happen if the type parameter was
1263+
// found via unqualified lookup, but the current context's
1264+
// generic signature failed to build because of circularity or
1265+
// completion failure.
1266+
return result.subst(QueryInterfaceTypeSubstitutions{genericEnv},
1267+
LookUpConformanceInModule(),
1268+
SubstFlags::PreservePackExpansionLevel);
1269+
}
1270+
}
1271+
return result;
1272+
};
1273+
12501274
// Check the generic arguments against the requirements of the declaration's
12511275
// generic signature.
12521276
if (!skipRequirementsCheck && getStage() == TypeResolutionStage::Interface) {
1253-
// Check the generic arguments against the requirements of the declaration's
1254-
// generic signature.
1277+
if (hasTypeVariables) {
1278+
ASSERT(requirementOpener && "Must have requirement opener for type vars");
1279+
requirementOpener(decl, substitutions);
1280+
} else {
1281+
SourceLoc noteLoc = decl->getLoc();
1282+
if (noteLoc.isInvalid())
1283+
noteLoc = loc;
12551284

1256-
SourceLoc noteLoc = decl->getLoc();
1257-
if (noteLoc.isInvalid())
1258-
noteLoc = loc;
1285+
auto genericSig = decl->getGenericSignature();
12591286

1260-
auto genericSig = decl->getGenericSignature();
1261-
const auto substitutions = [&](SubstitutableType *type) -> Type {
1262-
auto result = QueryTypeSubstitutionMap{subs}(type);
1263-
if (result->hasTypeParameter()) {
1264-
if (const auto contextSig = getGenericSignature()) {
1265-
auto *genericEnv = contextSig.getGenericEnvironment();
1266-
// FIXME: This should just use mapTypeIntoContext(), but we can't yet
1267-
// because we sometimes have type parameters here that are invalid for
1268-
// our generic signature. This can happen if the type parameter was
1269-
// found via unqualified lookup, but the current context's
1270-
// generic signature failed to build because of circularity or
1271-
// completion failure.
1272-
return result.subst(QueryInterfaceTypeSubstitutions{genericEnv},
1273-
LookUpConformanceInModule(),
1274-
SubstFlags::PreservePackExpansionLevel);
1287+
const auto result = TypeChecker::checkGenericArgumentsForDiagnostics(
1288+
genericSig, substitutions);
1289+
switch (result.getKind()) {
1290+
case CheckRequirementsResult::RequirementFailure:
1291+
if (loc.isValid()) {
1292+
TypeChecker::diagnoseRequirementFailure(
1293+
result.getRequirementFailureInfo(), loc, noteLoc,
1294+
UnboundGenericType::get(decl, parentTy, ctx),
1295+
genericSig.getGenericParams(), substitutions);
12751296
}
1276-
}
1277-
return result;
1278-
};
12791297

1280-
const auto result = TypeChecker::checkGenericArgumentsForDiagnostics(
1281-
genericSig, substitutions);
1282-
switch (result.getKind()) {
1283-
case CheckRequirementsResult::RequirementFailure:
1284-
if (loc.isValid()) {
1285-
TypeChecker::diagnoseRequirementFailure(
1286-
result.getRequirementFailureInfo(), loc, noteLoc,
1287-
UnboundGenericType::get(decl, parentTy, ctx),
1288-
genericSig.getGenericParams(), substitutions);
1298+
LLVM_FALLTHROUGH;
1299+
case CheckRequirementsResult::SubstitutionFailure:
1300+
return ErrorType::get(ctx);
1301+
case CheckRequirementsResult::Success:
1302+
break;
12891303
}
1290-
1291-
LLVM_FALLTHROUGH;
1292-
case CheckRequirementsResult::SubstitutionFailure:
1293-
return ErrorType::get(ctx);
1294-
case CheckRequirementsResult::Success:
1295-
break;
12961304
}
12971305
}
12981306

@@ -2564,22 +2572,22 @@ Type TypeResolution::resolveContextualType(
25642572
TypeRepr *TyR, DeclContext *dc, TypeResolutionOptions opts,
25652573
OpenUnboundGenericTypeFn unboundTyOpener,
25662574
HandlePlaceholderTypeReprFn placeholderHandler,
2567-
OpenPackElementFn packElementOpener,
2575+
OpenPackElementFn packElementOpener, OpenRequirementFn requirementOpener,
25682576
SILTypeResolutionContext *silContext) {
2569-
return resolveContextualType(TyR, dc, dc->getGenericSignatureOfContext(),
2570-
opts, unboundTyOpener, placeholderHandler,
2571-
packElementOpener, silContext);
2577+
return resolveContextualType(
2578+
TyR, dc, dc->getGenericSignatureOfContext(), opts, unboundTyOpener,
2579+
placeholderHandler, packElementOpener, requirementOpener, silContext);
25722580
}
25732581

25742582
Type TypeResolution::resolveContextualType(
25752583
TypeRepr *TyR, DeclContext *dc, GenericSignature genericSig,
25762584
TypeResolutionOptions opts, OpenUnboundGenericTypeFn unboundTyOpener,
25772585
HandlePlaceholderTypeReprFn placeholderHandler,
2578-
OpenPackElementFn packElementOpener,
2586+
OpenPackElementFn packElementOpener, OpenRequirementFn requirementOpener,
25792587
SILTypeResolutionContext *silContext) {
25802588
const auto resolution = TypeResolution::forInterface(
25812589
dc, genericSig, opts, unboundTyOpener, placeholderHandler,
2582-
packElementOpener);
2590+
packElementOpener, requirementOpener);
25832591
const auto ty = resolution.resolveType(TyR, silContext);
25842592

25852593
return GenericEnvironment::mapTypeIntoContext(
@@ -4384,11 +4392,10 @@ NeverNullType TypeResolver::resolveSILBoxType(SILBoxTypeRepr *repr,
43844392
auto *genericParams = repr->getGenericParams();
43854393

43864394
if (genericParams) {
4387-
fieldResolution =
4388-
TypeResolution::forInterface(getDeclContext(), genericSig, options,
4389-
resolution.getUnboundTypeOpener(),
4390-
resolution.getPlaceholderHandler(),
4391-
resolution.getPackElementOpener());
4395+
fieldResolution = TypeResolution::forInterface(
4396+
getDeclContext(), genericSig, options,
4397+
resolution.getUnboundTypeOpener(), resolution.getPlaceholderHandler(),
4398+
resolution.getPackElementOpener(), resolution.getRequirementOpener());
43924399
}
43934400

43944401
SILInnerGenericContextRAII scope(silContext, genericParams);
@@ -4593,9 +4600,8 @@ NeverNullType TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr,
45934600
if (componentTypeSig) {
45944601
functionResolution = TypeResolution::forInterface(
45954602
getDeclContext(), componentTypeSig, options,
4596-
resolution.getUnboundTypeOpener(),
4597-
resolution.getPlaceholderHandler(),
4598-
resolution.getPackElementOpener());
4603+
resolution.getUnboundTypeOpener(), resolution.getPlaceholderHandler(),
4604+
resolution.getPackElementOpener(), resolution.getRequirementOpener());
45994605
}
46004606

46014607
SILInnerGenericContextRAII innerGenericContext(silContext,
@@ -4651,11 +4657,10 @@ NeverNullType TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr,
46514657
SubstitutionMap patternSubs;
46524658
if (!repr->getPatternSubstitutions().empty()) {
46534659
if (genericSig) {
4654-
auto resolveSILParameters =
4655-
TypeResolution::forInterface(getDeclContext(), genericSig, options,
4656-
resolution.getUnboundTypeOpener(),
4657-
resolution.getPlaceholderHandler(),
4658-
resolution.getPackElementOpener());
4660+
auto resolveSILParameters = TypeResolution::forInterface(
4661+
getDeclContext(), genericSig, options,
4662+
resolution.getUnboundTypeOpener(), resolution.getPlaceholderHandler(),
4663+
resolution.getPackElementOpener(), resolution.getRequirementOpener());
46594664
patternSubs = resolveSubstitutions(repr->getPatternGenericSignature(),
46604665
repr->getPatternSubstitutions(),
46614666
TypeResolver{resolveSILParameters,

0 commit comments

Comments
 (0)