Skip to content

Commit 9c89820

Browse files
authored
Merge pull request swiftlang#83870 from hamishknight/overrun
[CS] Open generic requirements for types with unbound + placeholder types
2 parents 45f7952 + 2e0be5a commit 9c89820

File tree

9 files changed

+356
-132
lines changed

9 files changed

+356
-132
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5800,6 +5800,23 @@ class OpenUnboundGenericType {
58005800
}
58015801
};
58025802

5803+
/// A function object suitable for use as an \c OpenRequirementFn that "opens"
5804+
/// the requirements for a given type's generic signature given a set of
5805+
/// argument substitutions.
5806+
class OpenGenericTypeRequirements {
5807+
ConstraintSystem &cs;
5808+
const ConstraintLocatorBuilder &locator;
5809+
PreparedOverloadBuilder *preparedOverload;
5810+
5811+
public:
5812+
explicit OpenGenericTypeRequirements(
5813+
ConstraintSystem &cs, const ConstraintLocatorBuilder &locator,
5814+
PreparedOverloadBuilder *preparedOverload)
5815+
: cs(cs), locator(locator), preparedOverload(preparedOverload) {}
5816+
5817+
void operator()(GenericTypeDecl *decl, TypeSubstitutionFn subst) const;
5818+
};
5819+
58035820
class HandlePlaceholderType {
58045821
ConstraintSystem &cs;
58055822
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)