Skip to content

Commit c0312b9

Browse files
committed
[ConstraintSystem] Record holes in the constraint system using a new flag in
`TypeVariableOptions` rather than using a separate data structure in the constraint system.
1 parent ea1a46c commit c0312b9

File tree

10 files changed

+65
-72
lines changed

10 files changed

+65
-72
lines changed

include/swift/AST/Types.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -347,12 +347,10 @@ class alignas(1 << TypeAlignInBits) TypeBase {
347347
NumProtocols : 16
348348
);
349349

350-
SWIFT_INLINE_BITFIELD_FULL(TypeVariableType, TypeBase, 4+32,
351-
: NumPadBits,
352-
350+
SWIFT_INLINE_BITFIELD_FULL(TypeVariableType, TypeBase, 5+32,
353351
/// Type variable options.
354-
Options : 4,
355-
352+
Options : 5,
353+
: NumPadBits,
356354
/// The unique number assigned to this type variable.
357355
ID : 32
358356
);

lib/Sema/CSBindings.cpp

Lines changed: 2 additions & 3 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,

lib/Sema/CSDiagnostics.cpp

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

3164+
bool hasUnresolvedPattern = false;
3165+
anchor->forEachChildExpr([&](Expr *expr) {
3166+
hasUnresolvedPattern |= isa<UnresolvedPatternExpr>(expr);
3167+
return hasUnresolvedPattern ? nullptr : expr;
3168+
});
3169+
if (hasUnresolvedPattern && !baseType->getAs<EnumType>()) {
3170+
emitDiagnostic(anchor->getLoc(),
3171+
diag::cannot_match_unresolved_expr_pattern_with_value, baseType);
3172+
return;
3173+
}
3174+
31643175
emitDiagnostic(anchor->getLoc(), diagnostic, baseType, getName())
31653176
.highlight(baseExpr->getSourceRange())
31663177
.highlight(nameLoc.getSourceRange());

lib/Sema/CSSimplify.cpp

Lines changed: 16 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -867,9 +867,7 @@ class ArgumentFailureTracker : public MatchCallArgumentListener {
867867

868868
auto *argType =
869869
CS.createTypeVariable(argLoc, TVO_CanBindToInOut | TVO_CanBindToLValue |
870-
TVO_CanBindToNoEscape);
871-
872-
CS.recordPotentialHole(argType);
870+
TVO_CanBindToNoEscape | TVO_CanBindToHole);
873871

874872
Arguments.push_back(param.withType(argType));
875873
++NumSynthesizedArgs;
@@ -4954,6 +4952,12 @@ ConstraintSystem::simplifyFunctionComponentConstraint(
49544952
// Track how many times we do this so that we can record a fix for each.
49554953
++unwrapCount;
49564954
}
4955+
4956+
if (simplified->isHole()) {
4957+
if (auto *typeVar = second->getAs<TypeVariableType>())
4958+
recordPotentialHole(typeVar);
4959+
return SolutionKind::Solved;
4960+
}
49574961
}
49584962

49594963
if (simplified->isTypeVariableOrMember()) {
@@ -6743,17 +6747,21 @@ ConstraintSystem::simplifyKeyPathConstraint(
67436747
}
67446748

67456749
if (shouldAttemptFixes()) {
6746-
auto *componentLoc = getConstraintLocator(
6747-
keyPath, {LocatorPathElt::KeyPathComponent(i),
6748-
LocatorPathElt::KeyPathComponentResult()});
6750+
auto typeVar =
6751+
llvm::find_if(componentTypeVars, [&](TypeVariableType *typeVar) {
6752+
auto *locator = typeVar->getImpl().getLocator();
6753+
auto elt = locator->findLast<LocatorPathElt::KeyPathComponent>();
6754+
return elt && elt->getIndex() == i;
6755+
});
67496756

67506757
// If one of the components haven't been resolved, let's check
67516758
// whether it has been determined to be a "hole" and if so,
67526759
// let's allow component validation to contiunue.
67536760
//
67546761
// This helps to, for example, diagnose problems with missing
67556762
// members used as part of a key path.
6756-
if (isPotentialHoleAt(componentLoc)) {
6763+
if (typeVar != componentTypeVars.end() &&
6764+
(*typeVar)->getImpl().canBindToHole()) {
67576765
anyComponentsUnresolved = true;
67586766
capability = ReadOnly;
67596767
continue;
@@ -7152,25 +7160,6 @@ ConstraintSystem::simplifyApplicableFnConstraint(
71527160
// following: $T1 -> $T2.
71537161
auto func1 = type1->castTo<FunctionType>();
71547162

7155-
// Let's check if this member couldn't be found and is fixed
7156-
// to exist based on its usage.
7157-
if (auto *memberTy = type2->getAs<TypeVariableType>()) {
7158-
if (isPotentialHole(memberTy)) {
7159-
auto *funcTy = type1->castTo<FunctionType>();
7160-
auto *locator = memberTy->getImpl().getLocator();
7161-
// Bind type variable associated with member to a type of argument
7162-
// application, which makes it seem like member exists with the
7163-
// types of the parameters matching argument types exactly.
7164-
addConstraint(ConstraintKind::Bind, memberTy, funcTy, locator);
7165-
// There might be no contextual type for result of the application,
7166-
// in cases like `let _ = x.foo()`, so let's record a potential hole.
7167-
auto resultTy = funcTy->getResult();
7168-
if (auto *typeVar = resultTy->getAs<TypeVariableType>())
7169-
recordPotentialHole(typeVar);
7170-
return SolutionKind::Solved;
7171-
}
7172-
}
7173-
71747163
// Before stripping lvalue-ness and optional types, save the original second
71757164
// type for handling `func callAsFunction` and `@dynamicCallable`
71767165
// applications. This supports the following cases:
@@ -8184,7 +8173,7 @@ bool ConstraintSystem::recordFix(ConstraintFix *fix, unsigned impact) {
81848173

81858174
void ConstraintSystem::recordPotentialHole(TypeVariableType *typeVar) {
81868175
assert(typeVar);
8187-
Holes.insert(typeVar->getImpl().getLocator());
8176+
typeVar->getImpl().enableCanBindToHole(getSavedBindings());
81888177
}
81898178

81908179
ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(

lib/Sema/CSSolver.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,6 @@ ConstraintSystem::SolverScope::SolverScope(ConstraintSystem &cs)
436436
numSavedBindings = cs.solverState->savedBindings.size();
437437
numConstraintRestrictions = cs.ConstraintRestrictions.size();
438438
numFixes = cs.Fixes.size();
439-
numHoles = cs.Holes.size();
440439
numFixedRequirements = cs.FixedRequirements.size();
441440
numDisjunctionChoices = cs.DisjunctionChoices.size();
442441
numOpenedTypes = cs.OpenedTypes.size();
@@ -484,9 +483,6 @@ ConstraintSystem::SolverScope::~SolverScope() {
484483
// Remove any fixes.
485484
truncate(cs.Fixes, numFixes);
486485

487-
// Remove any holes encountered along the current path.
488-
truncate(cs.Holes, numHoles);
489-
490486
// Remove any disjunction choices.
491487
truncate(cs.DisjunctionChoices, numDisjunctionChoices);
492488

lib/Sema/ConstraintSystem.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1120,7 +1120,8 @@ void ConstraintSystem::openGenericParameters(DeclContext *outerDC,
11201120
auto *paramLocator = getConstraintLocator(
11211121
locator.withPathElement(LocatorPathElt::GenericParameter(gp)));
11221122

1123-
auto typeVar = createTypeVariable(paramLocator, TVO_PrefersSubtypeBinding);
1123+
auto typeVar = createTypeVariable(paramLocator, TVO_PrefersSubtypeBinding |
1124+
TVO_CanBindToHole);
11241125
auto result = replacements.insert(std::make_pair(
11251126
cast<GenericTypeParamType>(gp->getCanonicalType()), typeVar));
11261127

lib/Sema/ConstraintSystem.h

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,12 @@ namespace constraints {
7171
/// A handle that holds the saved state of a type variable, which
7272
/// can be restored.
7373
class SavedTypeVariableBinding {
74-
/// The type variable and type variable options.
75-
llvm::PointerIntPair<TypeVariableType *, 4> TypeVarAndOptions;
76-
74+
/// The type variable that we saved the state of.
75+
TypeVariableType *TypeVar;
76+
77+
/// The saved type variable options.
78+
unsigned Options;
79+
7780
/// The parent or fixed type.
7881
llvm::PointerUnion<TypeVariableType *, TypeBase *> ParentOrFixed;
7982

@@ -82,9 +85,6 @@ class SavedTypeVariableBinding {
8285

8386
/// Restore the state of the type variable to the saved state.
8487
void restore();
85-
86-
TypeVariableType *getTypeVariable() { return TypeVarAndOptions.getPointer(); }
87-
unsigned getOptions() { return TypeVarAndOptions.getInt(); }
8888
};
8989

9090
/// A set of saved type variable bindings.
@@ -169,9 +169,12 @@ enum TypeVariableOptions {
169169
/// Whether the type variable can be bound to a non-escaping type or not.
170170
TVO_CanBindToNoEscape = 0x04,
171171

172+
/// Whether the type variable can be bound to a hole type or not.
173+
TVO_CanBindToHole = 0x08,
174+
172175
/// Whether a more specific deduction for this type variable implies a
173176
/// better solution to the constraint system.
174-
TVO_PrefersSubtypeBinding = 0x08,
177+
TVO_PrefersSubtypeBinding = 0x10,
175178
};
176179

177180
/// The implementation object for a type variable used within the
@@ -238,6 +241,9 @@ class TypeVariableType::Implementation {
238241
/// Whether this type variable can bind to an inout type.
239242
bool canBindToNoEscape() const { return getRawOptions() & TVO_CanBindToNoEscape; }
240243

244+
/// Whether this type variable can bind to a hole type.
245+
bool canBindToHole() const { return getRawOptions() & TVO_CanBindToHole; }
246+
241247
/// Whether this type variable prefers a subtype binding over a supertype
242248
/// binding.
243249
bool prefersSubtypeBinding() const {
@@ -427,6 +433,14 @@ class TypeVariableType::Implementation {
427433
~TVO_CanBindToNoEscape;
428434
}
429435

436+
void enableCanBindToHole(constraints::SavedTypeVariableBindings *record) {
437+
auto &impl = getRepresentative(record)->getImpl();
438+
if (record)
439+
impl.recordBinding(*record);
440+
441+
impl.getTypeVariable()->Bits.TypeVariableType.Options |= TVO_CanBindToHole;
442+
}
443+
430444
/// Print the type variable to the given output stream.
431445
void print(llvm::raw_ostream &OS);
432446
};
@@ -1107,13 +1121,6 @@ class ConstraintSystem {
11071121
/// The set of fixes applied to make the solution work.
11081122
llvm::SmallVector<ConstraintFix *, 4> Fixes;
11091123

1110-
/// The set of "holes" in the constraint system encountered
1111-
/// along the current path identified by locator. A "hole" is
1112-
/// a type variable which type couldn't be determined due to
1113-
/// an inference failure e.g. missing member, ambiguous generic
1114-
/// parameter which hasn't been explicitly specified.
1115-
llvm::SmallSetVector<ConstraintLocator *, 4> Holes;
1116-
11171124
/// The set of remembered disjunction choices used to reach
11181125
/// the current constraint system.
11191126
std::vector<std::pair<ConstraintLocator*, unsigned>>
@@ -1608,9 +1615,6 @@ class ConstraintSystem {
16081615
/// The length of \c Fixes.
16091616
unsigned numFixes;
16101617

1611-
/// The length of \c Holes.
1612-
unsigned numHoles;
1613-
16141618
/// The length of \c FixedRequirements.
16151619
unsigned numFixedRequirements;
16161620

@@ -2044,14 +2048,6 @@ class ConstraintSystem {
20442048

20452049
void recordPotentialHole(TypeVariableType *typeVar);
20462050

2047-
bool isPotentialHole(TypeVariableType *typeVar) const {
2048-
return isPotentialHoleAt(typeVar->getImpl().getLocator());
2049-
}
2050-
2051-
bool isPotentialHoleAt(ConstraintLocator *locator) const {
2052-
return bool(Holes.count(locator));
2053-
}
2054-
20552051
/// Determine whether constraint system already has a fix recorded
20562052
/// for a particular location.
20572053
bool hasFixFor(ConstraintLocator *locator,

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,12 @@ void TypeVariableType::Implementation::print(llvm::raw_ostream &OS) {
6868
}
6969

7070
SavedTypeVariableBinding::SavedTypeVariableBinding(TypeVariableType *typeVar)
71-
: TypeVarAndOptions(typeVar, typeVar->getImpl().getRawOptions()),
71+
: TypeVar(typeVar), Options(typeVar->getImpl().getRawOptions()),
7272
ParentOrFixed(typeVar->getImpl().ParentOrFixed) { }
7373

7474
void SavedTypeVariableBinding::restore() {
75-
auto *typeVar = getTypeVariable();
76-
typeVar->getImpl().setRawOptions(getOptions());
77-
typeVar->getImpl().ParentOrFixed = ParentOrFixed;
75+
TypeVar->getImpl().setRawOptions(Options);
76+
TypeVar->getImpl().ParentOrFixed = ParentOrFixed;
7877
}
7978

8079
GenericTypeParamType *

test/decl/init/nonnominal_init.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@ indirect enum Or<A, B> {
88
}
99

1010
func deMorgan<A, B>(_ ne: Not<Or<A, B>>) -> And<Not<A>, Not<B>> {
11+
// FIXME(diagnostics): The error message about initialization here is confusing
1112
return And<Not<A>, Not<B>>(
12-
Not<A> { a in ne(.left(a)) }, // expected-error {{non-nominal type 'Not<A>' (aka '(A) -> Never') does not support explicit initialization}}
13-
Not<B> { a in ne(.right(a)) }
13+
Not<A> { a in ne(.left(a)) }, // expected-error {{type 'Not<A>' (aka '(A) -> Never') has no member 'init'}}
14+
// expected-error@-1 {{type 'Or<A, B>' has no member 'left'}}
15+
Not<B> { a in ne(.right(a)) } // expected-error {{type 'Not<B>' (aka '(B) -> Never') has no member 'init'}}
16+
// expected-error@-1 {{type 'Or<A, B>' has no member 'right'}}
1417
)
1518
}
1619

test/expr/delayed-ident/static_var.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,5 @@ var _: HasClosure = .factoryOpt(3)
5050
// expected-error@-1 {{value of optional type '((Int) -> HasClosure)?' must be unwrapped to a value of type '(Int) -> HasClosure'}}
5151
// expected-note@-2 {{coalesce}}
5252
// expected-note@-3 {{force-unwrap}}
53-
var _: HasClosure = .factoryOpt!(4) // expected-error {{type '((Int) -> HasClosure)?' has no member 'factoryOpt'}}
53+
// FIXME: we should accept this
54+
var _: HasClosure = .factoryOpt!(4) // expected-error {{type 'Optional<_>' has no member 'factoryOpt'}}

0 commit comments

Comments
 (0)