Skip to content

Commit 75d60b3

Browse files
authored
Merge pull request #84279 from hamishknight/preserve-fatal-score
[CS] Bail from conjunction for non-zero `SK_Hole`
2 parents f78a3c7 + 63d63d8 commit 75d60b3

File tree

5 files changed

+40
-18
lines changed

5 files changed

+40
-18
lines changed

lib/Sema/CSGen.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1957,6 +1957,8 @@ namespace {
19571957
void addSpecializationConstraint(ConstraintLocator *locator, Type boundType,
19581958
SourceLoc lAngleLoc,
19591959
ArrayRef<TypeRepr *> specializationArgs) {
1960+
auto &ctx = CS.getASTContext();
1961+
19601962
// Resolve each type.
19611963
SmallVector<Type, 2> specializationArgTypes;
19621964
auto options =
@@ -1971,6 +1973,7 @@ namespace {
19711973
options |= TypeResolutionFlags::AllowPackReferences;
19721974
elementEnv = OuterExpansions.back();
19731975
}
1976+
auto alreadyInvalid = specializationArg->isInvalid();
19741977
auto result = TypeResolution::resolveContextualType(
19751978
specializationArg, CurDC, options,
19761979
// Introduce type variables for unbound generics.
@@ -1980,17 +1983,20 @@ namespace {
19801983
OpenGenericTypeRequirements(CS, locator,
19811984
/*preparedOverload*/ nullptr));
19821985
if (result->hasError()) {
1983-
auto &ctxt = CS.getASTContext();
1984-
result = PlaceholderType::get(ctxt, specializationArg);
1985-
ctxt.Diags.diagnose(lAngleLoc,
1986-
diag::while_parsing_as_left_angle_bracket);
1986+
if (!alreadyInvalid) {
1987+
ctx.Diags.diagnose(lAngleLoc,
1988+
diag::while_parsing_as_left_angle_bracket);
1989+
}
1990+
CS.recordFix(IgnoreInvalidASTNode::create(
1991+
CS, CS.getConstraintLocator(argLocator)));
1992+
result = PlaceholderType::get(ctx, specializationArg);
19871993
}
19881994
specializationArgTypes.push_back(result);
19891995
}
19901996

19911997
auto constraint = Constraint::create(
19921998
CS, ConstraintKind::ExplicitGenericArguments, boundType,
1993-
PackType::get(CS.getASTContext(), specializationArgTypes), locator);
1999+
PackType::get(ctx, specializationArgTypes), locator);
19942000
CS.addUnsolvedConstraint(constraint);
19952001
CS.activateConstraint(constraint);
19962002
}

lib/Sema/CSStep.cpp

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -887,23 +887,24 @@ StepResult ConjunctionStep::resume(bool prevFailed) {
887887
if (Solutions.size() > 1)
888888
filterSolutions(Solutions, /*minimize=*/true);
889889

890-
// In diagnostic mode we need to stop a conjunction
891-
// but consider it successful if there are:
890+
// In diagnostic mode we need to stop a conjunction but consider it
891+
// successful if there are:
892892
//
893-
// - More than one solution for this element. Ambiguity
894-
// needs to get propagated back to the outer context
895-
// to be diagnosed.
896-
// - A single solution that requires one or more fixes,
897-
// continuing would result in more errors associated
898-
// with the failed element.
893+
// - More than one solution for this element. Ambiguity needs to get
894+
// propagated back to the outer context to be diagnosed.
895+
// - A single solution that requires one or more fixes or holes, since
896+
// continuing would result in more errors associated with the failed
897+
// element, and we don't preserve scores across elements.
899898
if (CS.shouldAttemptFixes()) {
900899
if (Solutions.size() > 1)
901900
Producer.markExhausted();
902901

903902
if (Solutions.size() == 1) {
904903
auto score = Solutions.front().getFixedScore();
905-
if (score.Data[SK_Fix] > 0 && !CS.isForCodeCompletion())
906-
Producer.markExhausted();
904+
if (!CS.isForCodeCompletion()) {
905+
if (score.Data[SK_Fix] > 0 || score.Data[SK_Hole] > 0)
906+
Producer.markExhausted();
907+
}
907908
}
908909
} else if (Solutions.size() != 1) {
909910
return failConjunction();
@@ -1053,7 +1054,7 @@ void ConjunctionStep::SolverSnapshot::replaySolution(const Solution &solution) {
10531054

10541055
// If inference succeeded, we are done.
10551056
auto score = solution.getFixedScore();
1056-
if (score.Data[SK_Fix] == 0)
1057+
if (score.Data[SK_Fix] == 0 && score.Data[SK_Hole] == 0)
10571058
return;
10581059

10591060
// If this conjunction represents a closure and inference

test/Constraints/generics.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,3 +1113,18 @@ func testHolePropagation() {
11131113
_ = { () -> (S<R>, Int) in return (makeT(), 0) } // expected-error {{type 'R' does not conform to protocol 'P'}}
11141114
_ = { () -> (S<R>, Int) in (); return (makeT(), 0) } // expected-error {{type 'R' does not conform to protocol 'P'}}
11151115
}
1116+
1117+
@freestanding(expression) macro overloadedMacro<T>() -> String = #file
1118+
@freestanding(expression) macro overloadedMacro<T>(_ x: T = 0) -> String = #file
1119+
1120+
do {
1121+
func foo(_ fn: () -> Int) {}
1122+
func foo(_ fn: () -> String) {}
1123+
1124+
// Make sure we only emit a single note here.
1125+
foo {
1126+
#overloadedMacro < Undefined >
1127+
// expected-error@-1 {{cannot find type 'Undefined' in scope}}
1128+
// expected-note@-2 {{while parsing this '<' as a type parameter bracket}}
1129+
}
1130+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// {"kind":"typecheck","signature":"(anonymous namespace)::ExprWalker::walkToExprPost(swift::Expr*)","signatureAssert":"Assertion failed: (Ptr && \"Cannot dereference a null Type!\"), function operator->"}
2-
// RUN: not --crash %target-swift-frontend -typecheck %s
2+
// RUN: not %target-swift-frontend -typecheck %s
33
func a {
44
{
55
\ b() a
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
// {"kind":"typecheck","signature":"swift::constraints::SolverTrail::~SolverTrail()","signatureAssert":"Assertion failed: (Changes.empty() && \"Trail corrupted\"), function ~SolverTrail"}
2-
// RUN: not --crash %target-swift-frontend -typecheck %s
2+
// RUN: not %target-swift-frontend -typecheck %s
33
enum a< b { case c(}
44
func d< b >(b->a< b >) d(a< e >.c let a

0 commit comments

Comments
 (0)