Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1957,6 +1957,8 @@ namespace {
void addSpecializationConstraint(ConstraintLocator *locator, Type boundType,
SourceLoc lAngleLoc,
ArrayRef<TypeRepr *> specializationArgs) {
auto &ctx = CS.getASTContext();

// Resolve each type.
SmallVector<Type, 2> specializationArgTypes;
auto options =
Expand All @@ -1971,6 +1973,7 @@ namespace {
options |= TypeResolutionFlags::AllowPackReferences;
elementEnv = OuterExpansions.back();
}
auto alreadyInvalid = specializationArg->isInvalid();
auto result = TypeResolution::resolveContextualType(
specializationArg, CurDC, options,
// Introduce type variables for unbound generics.
Expand All @@ -1980,17 +1983,20 @@ namespace {
OpenGenericTypeRequirements(CS, locator,
/*preparedOverload*/ nullptr));
if (result->hasError()) {
auto &ctxt = CS.getASTContext();
result = PlaceholderType::get(ctxt, specializationArg);
ctxt.Diags.diagnose(lAngleLoc,
diag::while_parsing_as_left_angle_bracket);
if (!alreadyInvalid) {
ctx.Diags.diagnose(lAngleLoc,
diag::while_parsing_as_left_angle_bracket);
}
CS.recordFix(IgnoreInvalidASTNode::create(
CS, CS.getConstraintLocator(argLocator)));
result = PlaceholderType::get(ctx, specializationArg);
}
specializationArgTypes.push_back(result);
}

auto constraint = Constraint::create(
CS, ConstraintKind::ExplicitGenericArguments, boundType,
PackType::get(CS.getASTContext(), specializationArgTypes), locator);
PackType::get(ctx, specializationArgTypes), locator);
CS.addUnsolvedConstraint(constraint);
CS.activateConstraint(constraint);
}
Expand Down
23 changes: 12 additions & 11 deletions lib/Sema/CSStep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -887,23 +887,24 @@ StepResult ConjunctionStep::resume(bool prevFailed) {
if (Solutions.size() > 1)
filterSolutions(Solutions, /*minimize=*/true);

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

if (Solutions.size() == 1) {
auto score = Solutions.front().getFixedScore();
if (score.Data[SK_Fix] > 0 && !CS.isForCodeCompletion())
Producer.markExhausted();
if (!CS.isForCodeCompletion()) {
if (score.Data[SK_Fix] > 0 || score.Data[SK_Hole] > 0)
Producer.markExhausted();
}
}
} else if (Solutions.size() != 1) {
return failConjunction();
Expand Down Expand Up @@ -1053,7 +1054,7 @@ void ConjunctionStep::SolverSnapshot::replaySolution(const Solution &solution) {

// If inference succeeded, we are done.
auto score = solution.getFixedScore();
if (score.Data[SK_Fix] == 0)
if (score.Data[SK_Fix] == 0 && score.Data[SK_Hole] == 0)
return;

// If this conjunction represents a closure and inference
Expand Down
15 changes: 15 additions & 0 deletions test/Constraints/generics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1113,3 +1113,18 @@ func testHolePropagation() {
_ = { () -> (S<R>, Int) in return (makeT(), 0) } // expected-error {{type 'R' does not conform to protocol 'P'}}
_ = { () -> (S<R>, Int) in (); return (makeT(), 0) } // expected-error {{type 'R' does not conform to protocol 'P'}}
}

@freestanding(expression) macro overloadedMacro<T>() -> String = #file
@freestanding(expression) macro overloadedMacro<T>(_ x: T = 0) -> String = #file

do {
func foo(_ fn: () -> Int) {}
func foo(_ fn: () -> String) {}

// Make sure we only emit a single note here.
foo {
#overloadedMacro < Undefined >
// expected-error@-1 {{cannot find type 'Undefined' in scope}}
// expected-note@-2 {{while parsing this '<' as a type parameter bracket}}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// {"kind":"typecheck","signature":"(anonymous namespace)::ExprWalker::walkToExprPost(swift::Expr*)","signatureAssert":"Assertion failed: (Ptr && \"Cannot dereference a null Type!\"), function operator->"}
// RUN: not --crash %target-swift-frontend -typecheck %s
// RUN: not %target-swift-frontend -typecheck %s
func a {
{
\ b() a
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// {"kind":"typecheck","signature":"swift::constraints::SolverTrail::~SolverTrail()","signatureAssert":"Assertion failed: (Changes.empty() && \"Trail corrupted\"), function ~SolverTrail"}
// RUN: not --crash %target-swift-frontend -typecheck %s
// RUN: not %target-swift-frontend -typecheck %s
enum a< b { case c(}
func d< b >(b->a< b >) d(a< e >.c let a