Skip to content

Commit eeb0675

Browse files
authored
Merge pull request swiftlang#84003 from hamishknight/minesweeper
2 parents a80ba34 + 2877223 commit eeb0675

17 files changed

+131
-34
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2681,8 +2681,11 @@ bool TypeVarBindingProducer::computeNext() {
26812681
// let's have it try `Void` as well because there is an
26822682
// implicit conversion `() -> T` to `() -> Void` and this
26832683
// helps to avoid creating a thunk to support it.
2684+
// Avoid doing this is we already have a hole binding since
2685+
// introducing Void will just cause local solution ambiguities.
26842686
if (getLocator()->isLastElement<LocatorPathElt::ClosureResult>() &&
2685-
binding.Kind == AllowedBindingKind::Supertypes) {
2687+
binding.Kind == AllowedBindingKind::Supertypes &&
2688+
!binding.BindingType->isPlaceholder()) {
26862689
auto voidType = CS.getASTContext().TheEmptyTupleType;
26872690
addNewBinding(binding.withSameSource(voidType, BindingKind::Exact));
26882691
}

lib/Sema/CSGen.cpp

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1716,8 +1716,13 @@ namespace {
17161716
CS.recordFix(
17171717
IgnoreInvalidASTNode::create(CS, CS.getConstraintLocator(locator)));
17181718

1719-
return CS.createTypeVariable(CS.getConstraintLocator(repr),
1720-
TVO_CanBindToHole);
1719+
// Immediately bind the result to a hole since we know it's invalid and
1720+
// want it to propagate rather than allowing other type variables to
1721+
// become holes.
1722+
auto *tv = CS.createTypeVariable(CS.getConstraintLocator(repr),
1723+
TVO_CanBindToHole);
1724+
CS.recordTypeVariablesAsHoles(tv);
1725+
return tv;
17211726
}
17221727
// Diagnose top-level usages of placeholder types.
17231728
if (auto *ty = dyn_cast<PlaceholderTypeRepr>(repr->getWithoutParens())) {
@@ -4908,16 +4913,27 @@ bool ConstraintSystem::generateConstraints(
49084913
return convertTypeLocator;
49094914
};
49104915

4911-
// Substitute type variables in for placeholder types.
4912-
convertType = convertType.transformRec([&](Type type) -> std::optional<Type> {
4913-
if (type->is<PlaceholderType>()) {
4914-
return Type(createTypeVariable(getLocator(type),
4915-
TVO_CanBindToNoEscape |
4916-
TVO_PrefersSubtypeBinding |
4917-
TVO_CanBindToHole));
4918-
}
4919-
return std::nullopt;
4920-
});
4916+
// If the contextual type has an error, we can't apply the solution.
4917+
// Record a fix for an invalid AST node.
4918+
if (convertType->hasError())
4919+
recordFix(IgnoreInvalidASTNode::create(*this, convertTypeLocator));
4920+
4921+
// Substitute type variables in for placeholder and error types.
4922+
convertType =
4923+
convertType.transformRec([&](Type type) -> std::optional<Type> {
4924+
if (!isa<PlaceholderType, ErrorType>(type.getPointer()))
4925+
return std::nullopt;
4926+
4927+
auto flags = TVO_CanBindToNoEscape | TVO_PrefersSubtypeBinding |
4928+
TVO_CanBindToHole;
4929+
auto tv = Type(createTypeVariable(getLocator(type), flags));
4930+
// For ErrorTypes we want to eagerly bind to a hole since we
4931+
// know this is where the issue is.
4932+
if (isa<ErrorType>(type.getPointer())) {
4933+
recordTypeVariablesAsHoles(tv);
4934+
}
4935+
return tv;
4936+
});
49214937

49224938
addContextualConversionConstraint(expr, convertType, ctp,
49234939
convertTypeLocator);

lib/Sema/CSSimplify.cpp

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5569,6 +5569,17 @@ bool ConstraintSystem::repairFailures(
55695569
return true;
55705570
};
55715571

5572+
// Propagate a hole from one type to another. This is useful for contextual
5573+
// types since type resolution forms a top-level ErrorType for types with
5574+
// nested errors, e.g `S<@error_type>` becomes `@error_type`. As such, when
5575+
// matching `S<$T0> == $T1` where `$T1` is a hole from a contextual type, we
5576+
// want to eagerly turn `$T0` into a hole since it's likely that `$T1` would
5577+
// have provided the contextual info for it.
5578+
auto tryPropagateHole = [&](Type from, Type to) {
5579+
if (from->isPlaceholder() && to->hasTypeVariable())
5580+
recordTypeVariablesAsHoles(to);
5581+
};
5582+
55725583
if (path.empty()) {
55735584
if (!anchor)
55745585
return false;
@@ -6342,6 +6353,13 @@ bool ConstraintSystem::repairFailures(
63426353

63436354
case ConstraintLocator::ClosureBody:
63446355
case ConstraintLocator::ClosureResult: {
6356+
// If either type is a placeholder, consider this fixed, eagerly propagating
6357+
// a hole from the contextual type.
6358+
if (lhs->isPlaceholder() || rhs->isPlaceholder()) {
6359+
tryPropagateHole(rhs, lhs);
6360+
return true;
6361+
}
6362+
63456363
if (repairByInsertingExplicitCall(lhs, rhs))
63466364
break;
63476365

@@ -6361,9 +6379,12 @@ bool ConstraintSystem::repairFailures(
63616379
}
63626380

63636381
case ConstraintLocator::ContextualType: {
6364-
// If either type is a placeholder, consider this fixed
6365-
if (lhs->isPlaceholder() || rhs->isPlaceholder())
6382+
// If either type is a placeholder, consider this fixed, eagerly propagating
6383+
// a hole from the contextual type.
6384+
if (lhs->isPlaceholder() || rhs->isPlaceholder()) {
6385+
tryPropagateHole(rhs, lhs);
63666386
return true;
6387+
}
63676388

63686389
// If either side is not yet resolved, it's too early for this fix.
63696390
if (lhs->isTypeVariableOrMember() || rhs->isTypeVariableOrMember())
@@ -7002,6 +7023,13 @@ bool ConstraintSystem::repairFailures(
70027023
}
70037024

70047025
case ConstraintLocator::CoercionOperand: {
7026+
// If either type is a placeholder, consider this fixed, eagerly propagating
7027+
// a hole from the contextual type.
7028+
if (lhs->isPlaceholder() || rhs->isPlaceholder()) {
7029+
tryPropagateHole(rhs, lhs);
7030+
return true;
7031+
}
7032+
70057033
auto *coercion = castToExpr<CoerceExpr>(anchor);
70067034

70077035
// Coercion from T.Type to T.Protocol.

lib/Sema/CSSyntacticElement.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -845,12 +845,6 @@ class SyntacticElementConstraintGenerator
845845
ContextualPattern::forPatternBindingDecl(patternBinding, index);
846846
Type patternType = TypeChecker::typeCheckPattern(contextualPattern);
847847

848-
// Fail early if pattern couldn't be type-checked.
849-
if (!patternType || patternType->hasError()) {
850-
hadError = true;
851-
return;
852-
}
853-
854848
auto target = getTargetForPattern(patternBinding, index, patternType);
855849
if (!target) {
856850
hadError = true;

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -876,11 +876,6 @@ bool TypeChecker::typeCheckPatternBinding(PatternBindingDecl *PBD,
876876
auto contextualPattern = ContextualPattern::forRawPattern(pattern, DC);
877877
patternType = typeCheckPattern(contextualPattern);
878878
}
879-
880-
if (patternType->hasError()) {
881-
PBD->setInvalid();
882-
return true;
883-
}
884879
}
885880

886881
bool hadError = TypeChecker::typeCheckBinding(pattern, init, DC, patternType,

lib/Sema/TypeCheckStmt.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1075,7 +1075,7 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
10751075
assert(TheFunc && "Should have bailed from pre-check if this is None");
10761076

10771077
Type ResultTy = TheFunc->getBodyResultType();
1078-
if (!ResultTy || ResultTy->hasError())
1078+
if (!ResultTy)
10791079
return nullptr;
10801080

10811081
if (!RS->hasResult()) {

lib/Sema/TypeOfReference.cpp

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -273,16 +273,32 @@ class InferableTypeOpener final {
273273
return substTy;
274274
}
275275

276+
Type transformErrorType(ErrorType *errTy) {
277+
// For ErrorTypes we want to eagerly bind to a hole since we know this is
278+
// where the issue is.
279+
auto *tv = createTypeVariable(cs.getConstraintLocator(locator));
280+
cs.recordTypeVariablesAsHoles(tv);
281+
return tv;
282+
}
283+
276284
Type transform(Type type) {
277285
if (!type)
278286
return type;
279-
if (!type->hasUnboundGenericType() && !type->hasPlaceholder())
287+
if (!type->hasUnboundGenericType() && !type->hasPlaceholder() &&
288+
!type->hasError()) {
280289
return type;
281-
290+
}
291+
// If the type has an error, we can't apply the solution. Record a fix for
292+
// an invalid AST node.
293+
if (type->hasError()) {
294+
cs.recordFix(
295+
IgnoreInvalidASTNode::create(cs, cs.getConstraintLocator(locator)));
296+
}
282297
return type.transformRec([&](Type type) -> std::optional<Type> {
283-
if (!type->hasUnboundGenericType() && !type->hasPlaceholder())
298+
if (!type->hasUnboundGenericType() && !type->hasPlaceholder() &&
299+
!type->hasError()) {
284300
return type;
285-
301+
}
286302
auto *tyPtr = type.getPointer();
287303
if (auto unbound = dyn_cast<UnboundGenericType>(tyPtr))
288304
return transformUnboundGenericType(unbound);
@@ -292,6 +308,8 @@ class InferableTypeOpener final {
292308
return transformBoundGenericType(genericTy);
293309
if (auto *aliasTy = dyn_cast<TypeAliasType>(tyPtr))
294310
return transformTypeAliasType(aliasTy);
311+
if (auto *errTy = dyn_cast<ErrorType>(tyPtr))
312+
return transformErrorType(errTy);
295313

296314
return std::nullopt;
297315
});

test/ClangImporter/overlay.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ Redeclaration.NSStringToNSString(AppKit.NSStringToNSString("abc")) // expected-w
1919

2020
let viaStruct: Redeclaration.FooStruct1 = AppKit.FooStruct1()
2121
let forwardDecl: Redeclaration.Tribool = AppKit.Tribool() // expected-error {{no type named 'Tribool' in module 'Redeclaration'}}
22+
// expected-error@-1 {{missing argument for parameter #1 in call}}

test/Constraints/generics.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,3 +1088,28 @@ do {
10881088
f(x, { $0 }, { _ in Task {} }) // expected-warning {{result of 'Task<E>' initializer is unused}}
10891089
}
10901090
}
1091+
1092+
func testHolePropagation() {
1093+
struct S<T: P> {}
1094+
struct R {}
1095+
1096+
// The hole from the contextual type should propagate such that we don't
1097+
// complain about not being able to infer 'T'.
1098+
_ = { () -> S<R> in S() } // expected-error {{type 'R' does not conform to protocol 'P'}}
1099+
_ = { () -> S<R> in return S() } // expected-error {{type 'R' does not conform to protocol 'P'}}
1100+
_ = { () -> S<R> in (); return S() } // expected-error {{type 'R' does not conform to protocol 'P'}}
1101+
1102+
let _: () -> S<R> = { S() } // expected-error {{type 'R' does not conform to protocol 'P'}}
1103+
let _: () -> S<R> = { return S() } // expected-error {{type 'R' does not conform to protocol 'P'}}
1104+
let _: () -> S<R> = { (); return S() } // expected-error {{type 'R' does not conform to protocol 'P'}}
1105+
1106+
_ = { S() }() as S<R> // expected-error {{type 'R' does not conform to protocol 'P'}}
1107+
_ = { return S() }() as S<R> // expected-error {{type 'R' does not conform to protocol 'P'}}
1108+
_ = { (); return S() } as () -> S<R> // expected-error {{type 'R' does not conform to protocol 'P'}}
1109+
1110+
func makeT<T>() -> T {}
1111+
1112+
_ = { () -> (S<R>, Int) in (makeT(), 0) } // expected-error {{type 'R' does not conform to protocol 'P'}}
1113+
_ = { () -> (S<R>, Int) in return (makeT(), 0) } // expected-error {{type 'R' does not conform to protocol 'P'}}
1114+
_ = { () -> (S<R>, Int) in (); return (makeT(), 0) } // expected-error {{type 'R' does not conform to protocol 'P'}}
1115+
}

test/Constraints/invalid_constraint_lookup.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,5 @@ protocol Collection : _Collection, Sequence {
2727
}
2828
func insertionSort<C: Mutable> (_ elements: inout C, i: C.Index) { // expected-error {{cannot find type 'Mutable' in scope}} expected-error {{'Index' is not a member type of type 'C'}}
2929
var x: C.Iterator.Element = elements[i] // expected-error {{'Iterator' is not a member type of type 'C'}}
30+
// expected-error@-1 {{value of type 'C' has no subscripts}}
3031
}

0 commit comments

Comments
 (0)