Skip to content

Commit 5bb5006

Browse files
authored
Merge pull request swiftlang#28243 from hborla/missing-generic-args-refactoring
[ConstraintSystem] Missing generic args/hole refactoring
2 parents 8a61284 + c0312b9 commit 5bb5006

19 files changed

+175
-171
lines changed

include/swift/AST/Types.h

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ class RecursiveTypeProperties {
177177

178178
/// Does a type with these properties have an unresolved type somewhere in it?
179179
bool hasUnresolvedType() const { return Bits & HasUnresolvedType; }
180-
180+
181181
/// Is a type with these properties an lvalue?
182182
bool isLValue() const { return Bits & IsLValue; }
183183

@@ -349,12 +349,10 @@ class alignas(1 << TypeAlignInBits) TypeBase {
349349
NumProtocols : 16
350350
);
351351

352-
SWIFT_INLINE_BITFIELD_FULL(TypeVariableType, TypeBase, 4+32,
353-
: NumPadBits,
354-
352+
SWIFT_INLINE_BITFIELD_FULL(TypeVariableType, TypeBase, 5+32,
355353
/// Type variable options.
356-
Options : 4,
357-
354+
Options : 5,
355+
: NumPadBits,
358356
/// The unique number assigned to this type variable.
359357
ID : 32
360358
);
@@ -565,7 +563,12 @@ class alignas(1 << TypeAlignInBits) TypeBase {
565563
bool hasUnresolvedType() const {
566564
return getRecursiveProperties().hasUnresolvedType();
567565
}
568-
566+
567+
/// Determine whether this type involves a hole.
568+
bool hasHole() const {
569+
return getRecursiveProperties().hasUnresolvedType();
570+
}
571+
569572
/// Determine whether the type involves a context-dependent archetype.
570573
bool hasArchetype() const {
571574
return getRecursiveProperties().hasArchetype();

lib/Sema/CSApply.cpp

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7367,23 +7367,25 @@ bool ConstraintSystem::applySolutionFixes(Expr *E, const Solution &solution) {
73677367
return;
73687368

73697369
// Coalesce fixes with the same locator to avoid duplicating notes.
7370+
using ConstraintFixVector = llvm::SmallVector<ConstraintFix *, 4>;
73707371
llvm::SmallMapVector<ConstraintLocator *,
7371-
llvm::SmallVector<ConstraintFix *, 4>, 4> aggregatedFixes;
7372+
llvm::SmallMapVector<FixKind, ConstraintFixVector, 4>, 4> aggregatedFixes;
73727373
for (auto *fix : fixes->second)
7373-
aggregatedFixes[fix->getLocator()].push_back(fix);
7374+
aggregatedFixes[fix->getLocator()][fix->getKind()].push_back(fix);
73747375

73757376
for (auto fixesPerLocator : aggregatedFixes) {
7376-
auto fixes = fixesPerLocator.second;
7377-
auto *primaryFix = fixes[0];
7378-
ArrayRef<ConstraintFix *> secondaryFixes{fixes.begin() + 1, fixes.end()};
7379-
7380-
auto *coalescedFix = primaryFix->coalescedWith(secondaryFixes);
7381-
auto diagnosed = coalescedFix->diagnose();
7382-
if (coalescedFix->isWarning()) {
7383-
assert(diagnosed && "warnings should always be diagnosed");
7384-
(void)diagnosed;
7385-
} else {
7386-
DiagnosedAnyErrors |= diagnosed;
7377+
for (auto fixesPerKind : fixesPerLocator.second) {
7378+
auto fixes = fixesPerKind.second;
7379+
auto *primaryFix = fixes[0];
7380+
ArrayRef<ConstraintFix *> secondaryFixes{fixes.begin() + 1, fixes.end()};
7381+
7382+
auto diagnosed = primaryFix->coalesceAndDiagnose(secondaryFixes);
7383+
if (primaryFix->isWarning()) {
7384+
assert(diagnosed && "warnings should always be diagnosed");
7385+
(void)diagnosed;
7386+
} else {
7387+
DiagnosedAnyErrors |= diagnosed;
7388+
}
73877389
}
73887390
}
73897391
}

lib/Sema/CSBindings.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -734,10 +734,9 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
734734
constraint->getLocator()});
735735
}
736736

737-
// If we don't have any potential bindings, allow generic
738-
// parameters and potential holes to default to `Unresolved`.
737+
// If there are no bindings, typeVar may be a hole.
739738
if (shouldAttemptFixes() && result.Bindings.empty() &&
740-
(isPotentialHole(typeVar) || result.isGenericParameter())) {
739+
typeVar->getImpl().canBindToHole()) {
741740
result.IsHole = true;
742741
result.addPotentialBinding({getASTContext().TheUnresolvedType,
743742
AllowedBindingKind::Exact, ConstraintKind::Defaultable, nullptr,
@@ -991,11 +990,11 @@ bool TypeVariableBinding::attempt(ConstraintSystem &cs) const {
991990
cs.DefaultedConstraints.push_back(Binding.DefaultableBinding);
992991

993992
if (locator->isForGenericParameter() && type->isHole()) {
994-
// Drop `generic parameter '...'` part of the locator to group all of the
995-
// missing generic parameters related to the same path together.
993+
// Drop `generic parameter` locator element so that all missing
994+
// generic parameters related to the same path can be coalesced later.
996995
auto path = locator->getPath();
997996
auto genericParam = locator->getGenericParameter();
998-
auto *fix = ExplicitlySpecifyGenericArguments::create(cs, {genericParam},
997+
auto *fix = DefaultGenericArgument::create(cs, genericParam,
999998
cs.getConstraintLocator(locator->getAnchor(), path.drop_back()));
1000999
if (cs.recordFix(fix))
10011000
return true;

lib/Sema/CSDiagnostics.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3172,6 +3172,17 @@ bool MissingMemberFailure::diagnoseAsError() {
31723172
if (baseType->is<TupleType>())
31733173
diagnostic = diag::could_not_find_tuple_member;
31743174

3175+
bool hasUnresolvedPattern = false;
3176+
anchor->forEachChildExpr([&](Expr *expr) {
3177+
hasUnresolvedPattern |= isa<UnresolvedPatternExpr>(expr);
3178+
return hasUnresolvedPattern ? nullptr : expr;
3179+
});
3180+
if (hasUnresolvedPattern && !baseType->getAs<EnumType>()) {
3181+
emitDiagnostic(anchor->getLoc(),
3182+
diag::cannot_match_unresolved_expr_pattern_with_value, baseType);
3183+
return;
3184+
}
3185+
31753186
emitDiagnostic(anchor->getLoc(), diagnostic, baseType, getName())
31763187
.highlight(baseExpr->getSourceRange())
31773188
.highlight(nameLoc.getSourceRange());

lib/Sema/CSFix.cpp

Lines changed: 16 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -702,39 +702,28 @@ CollectionElementContextualMismatch::create(ConstraintSystem &cs, Type srcType,
702702
CollectionElementContextualMismatch(cs, srcType, dstType, locator);
703703
}
704704

705-
bool ExplicitlySpecifyGenericArguments::diagnose(bool asNote) const {
706-
auto &cs = getConstraintSystem();
707-
MissingGenericArgumentsFailure failure(cs, getParameters(),
708-
getLocator());
709-
return failure.diagnose(asNote);
710-
}
705+
bool DefaultGenericArgument::coalesceAndDiagnose(
706+
ArrayRef<ConstraintFix *> fixes, bool asNote) const {
707+
llvm::SmallVector<GenericTypeParamType *, 4> missingParams{Param};
711708

712-
ConstraintFix *
713-
ExplicitlySpecifyGenericArguments::coalescedWith(ArrayRef<ConstraintFix *> fixes) {
714-
if (fixes.empty())
715-
return this;
716-
717-
auto params = getParameters();
718-
llvm::SmallVector<GenericTypeParamType *, 4> missingParams{params.begin(),
719-
params.end()};
720709
for (auto *otherFix : fixes) {
721-
if (auto *fix = otherFix->getAs<ExplicitlySpecifyGenericArguments>()) {
722-
auto additionalParams = fix->getParameters();
723-
missingParams.append(additionalParams.begin(), additionalParams.end());
724-
}
710+
if (auto *fix = otherFix->getAs<DefaultGenericArgument>())
711+
missingParams.push_back(fix->Param);
725712
}
726713

727-
return ExplicitlySpecifyGenericArguments::create(getConstraintSystem(),
728-
missingParams, getLocator());
714+
auto &cs = getConstraintSystem();
715+
MissingGenericArgumentsFailure failure(cs, missingParams, getLocator());
716+
return failure.diagnose(asNote);
729717
}
730718

731-
ExplicitlySpecifyGenericArguments *ExplicitlySpecifyGenericArguments::create(
732-
ConstraintSystem &cs, ArrayRef<GenericTypeParamType *> params,
733-
ConstraintLocator *locator) {
734-
unsigned size = totalSizeToAlloc<GenericTypeParamType *>(params.size());
735-
void *mem = cs.getAllocator().Allocate(
736-
size, alignof(ExplicitlySpecifyGenericArguments));
737-
return new (mem) ExplicitlySpecifyGenericArguments(cs, params, locator);
719+
bool DefaultGenericArgument::diagnose(bool asNote) const {
720+
return coalesceAndDiagnose({}, asNote);
721+
}
722+
723+
DefaultGenericArgument *
724+
DefaultGenericArgument::create(ConstraintSystem &cs, GenericTypeParamType *param,
725+
ConstraintLocator *locator) {
726+
return new (cs.getAllocator()) DefaultGenericArgument(cs, param, locator);
738727
}
739728

740729
SkipUnhandledConstructInFunctionBuilder *

lib/Sema/CSFix.h

Lines changed: 48 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,11 @@ class Solution;
4747

4848
/// Describes the kind of fix to apply to the given constraint before
4949
/// visiting it.
50+
///
51+
/// Note: values 0 and 1 are reserved for empty and tombstone kinds.
5052
enum class FixKind : uint8_t {
5153
/// Introduce a '!' to force an optional unwrap.
52-
ForceOptional,
54+
ForceOptional = 2,
5355

5456
/// Unwrap an optional base when we have a member access.
5557
UnwrapOptionalBase,
@@ -181,10 +183,8 @@ enum class FixKind : uint8_t {
181183
/// function to `Void` to conform to expected result type.
182184
RemoveReturn,
183185

184-
/// Generic parameters could not be inferred and have to be explicitly
185-
/// specified in the source. This fix groups all of the missing arguments
186-
/// associated with single declaration.
187-
ExplicitlySpecifyGenericArguments,
186+
/// Default ambiguous generic arguments to \c Any
187+
DefaultGenericArgument,
188188

189189
/// Skip any unhandled constructs that occur within a closure argument that
190190
/// matches up with a
@@ -252,14 +252,18 @@ class ConstraintFix {
252252

253253
virtual std::string getName() const = 0;
254254

255-
/// Diagnose a failure associated with this fix given
256-
/// root expression and information from constraint system.
257-
virtual bool diagnose(bool asNote = false) const = 0;
258-
259-
virtual ConstraintFix *coalescedWith(ArrayRef<ConstraintFix *> fixes) {
260-
return this;
255+
/// Coalesce this fix with the given secondary fixes and diagnose the failure.
256+
///
257+
/// The default implementation ignores \c secondaryFixes and calls
258+
/// \c diagnose.
259+
virtual bool coalesceAndDiagnose(ArrayRef<ConstraintFix *> secondaryFixes,
260+
bool asNote = false) const {
261+
return diagnose(asNote);
261262
}
262263

264+
/// Diagnose a failure associated with this fix.
265+
virtual bool diagnose(bool asNote = false) const = 0;
266+
263267
void print(llvm::raw_ostream &Out) const;
264268

265269
SWIFT_DEBUG_DUMP;
@@ -1249,49 +1253,32 @@ class CollectionElementContextualMismatch final : public ContextualMismatch {
12491253
ConstraintLocator *locator);
12501254
};
12511255

1252-
class ExplicitlySpecifyGenericArguments final
1253-
: public ConstraintFix,
1254-
private llvm::TrailingObjects<ExplicitlySpecifyGenericArguments,
1255-
GenericTypeParamType *> {
1256-
friend TrailingObjects;
1257-
1258-
unsigned NumMissingParams;
1256+
class DefaultGenericArgument final : public ConstraintFix {
1257+
GenericTypeParamType *Param;
12591258

1260-
ExplicitlySpecifyGenericArguments(ConstraintSystem &cs,
1261-
ArrayRef<GenericTypeParamType *> params,
1262-
ConstraintLocator *locator)
1263-
: ConstraintFix(cs, FixKind::ExplicitlySpecifyGenericArguments, locator),
1264-
NumMissingParams(params.size()) {
1265-
assert(!params.empty());
1266-
std::uninitialized_copy(params.begin(), params.end(),
1267-
getParametersBuf().begin());
1268-
}
1259+
DefaultGenericArgument(ConstraintSystem &cs, GenericTypeParamType *param,
1260+
ConstraintLocator *locator)
1261+
: ConstraintFix(cs, FixKind::DefaultGenericArgument, locator),
1262+
Param(param) {}
12691263

12701264
public:
12711265
static bool classof(const ConstraintFix *fix) {
1272-
return fix->getKind() == FixKind::ExplicitlySpecifyGenericArguments;
1266+
return fix->getKind() == FixKind::DefaultGenericArgument;
12731267
}
12741268

12751269
std::string getName() const override {
1276-
return "default missing generic arguments to `Any`";
1270+
auto paramName = Param->getString();
1271+
return "default generic argument '" + paramName + "' to 'Any'";
12771272
}
12781273

1279-
ArrayRef<GenericTypeParamType *> getParameters() const {
1280-
return {getTrailingObjects<GenericTypeParamType *>(), NumMissingParams};
1281-
}
1274+
bool coalesceAndDiagnose(ArrayRef<ConstraintFix *> secondaryFixes,
1275+
bool asNote = false) const override;
12821276

12831277
bool diagnose(bool asNote = false) const override;
12841278

1285-
ConstraintFix *coalescedWith(ArrayRef<ConstraintFix *> fixes) override;
1286-
1287-
static ExplicitlySpecifyGenericArguments *
1288-
create(ConstraintSystem &cs, ArrayRef<GenericTypeParamType *> params,
1289-
ConstraintLocator *locator);
1290-
1291-
private:
1292-
MutableArrayRef<GenericTypeParamType *> getParametersBuf() {
1293-
return {getTrailingObjects<GenericTypeParamType *>(), NumMissingParams};
1294-
}
1279+
static DefaultGenericArgument *create(ConstraintSystem &cs,
1280+
GenericTypeParamType *param,
1281+
ConstraintLocator *locator);
12951282
};
12961283

12971284
class SkipUnhandledConstructInFunctionBuilder final : public ConstraintFix {
@@ -1553,4 +1540,23 @@ class TreatEphemeralAsNonEphemeral final : public AllowArgumentMismatch {
15531540
} // end namespace constraints
15541541
} // end namespace swift
15551542

1543+
namespace llvm {
1544+
template <>
1545+
struct DenseMapInfo<swift::constraints::FixKind> {
1546+
using FixKind = swift::constraints::FixKind;
1547+
static inline FixKind getEmptyKey() {
1548+
return static_cast<FixKind>(0);
1549+
}
1550+
static inline FixKind getTombstoneKey() {
1551+
return static_cast<FixKind>(1);
1552+
}
1553+
static unsigned getHashValue(FixKind kind) {
1554+
return static_cast<unsigned>(kind);
1555+
}
1556+
static bool isEqual(FixKind lhs, FixKind rhs) {
1557+
return lhs == rhs;
1558+
}
1559+
};
1560+
}
1561+
15561562
#endif // SWIFT_SEMA_CSFIX_H

0 commit comments

Comments
 (0)