diff --git a/include/swift/Sema/ConstraintSystem.h b/include/swift/Sema/ConstraintSystem.h index 56a3a2a3cfdda..84d1233eda1dd 100644 --- a/include/swift/Sema/ConstraintSystem.h +++ b/include/swift/Sema/ConstraintSystem.h @@ -5736,7 +5736,7 @@ class ConstraintSystem { /// If we aren't certain that we've emitted a diagnostic, emit a fallback /// diagnostic. - void maybeProduceFallbackDiagnostic(SyntacticElementTarget target) const; + void maybeProduceFallbackDiagnostic(SourceLoc loc) const; /// Check whether given AST node represents an argument of an application /// of some sort (call, operator invocation, subscript etc.) diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index f7fe4c546b8dc..21cfc75d3bbbc 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -10021,7 +10021,7 @@ ConstraintSystem::applySolution(Solution &solution, { const auto &score = solution.getFixedScore(); if (score.Data[SK_Fix] > numResolvableFixes || score.Data[SK_Hole] > 0) { - maybeProduceFallbackDiagnostic(target); + maybeProduceFallbackDiagnostic(target.getLoc()); return std::nullopt; } } diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 9fdfe3e85c442..6246d80988776 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -236,6 +236,11 @@ bool FailureDiagnostic::conformsToKnownProtocol( return TypeChecker::conformsToKnownProtocol(type, protocol); } +bool FallbackDiagnostic::diagnoseAsError() { + getConstraintSystem().maybeProduceFallbackDiagnostic(getLoc()); + return true; +} + Type RequirementFailure::getOwnerType() const { auto anchor = getAnchor(); // If diagnostic is anchored at assignment expression diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 33cdc11755b29..c9840495e87b4 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -210,6 +210,15 @@ class FailureDiagnostic { llvm::SmallVectorImpl &scratch) const; }; +/// Emits a fallback diagnostic message if no other error has been emitted. +class FallbackDiagnostic final : public FailureDiagnostic { +public: + FallbackDiagnostic(const Solution &solution, ConstraintLocator *locator) + : FailureDiagnostic(solution, locator) {} + + bool diagnoseAsError() override; +}; + /// Base class for all of the diagnostics related to generic requirement /// failures, provides common information like failed requirement, /// declaration where such requirement comes from, etc. diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index 37c247b48c42c..a3fa602bdad07 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -2187,7 +2187,10 @@ AllowKeyPathWithoutComponents::create(ConstraintSystem &cs, bool IgnoreInvalidResultBuilderBody::diagnose(const Solution &solution, bool asNote) const { - return true; // Already diagnosed by `matchResultBuilder`. + // This should already be diagnosed by `matchResultBuilder`, emit a fallback + // diagnostic if not. + FallbackDiagnostic diag(solution, getLocator()); + return diag.diagnose(asNote); } IgnoreInvalidResultBuilderBody * @@ -2198,7 +2201,10 @@ IgnoreInvalidResultBuilderBody::create(ConstraintSystem &cs, bool IgnoreInvalidASTNode::diagnose(const Solution &solution, bool asNote) const { - return true; // Already diagnosed by the producer of ErrorExpr or ErrorType. + // This should already be diagnosed by the producer of ErrorExpr or ErrorType, + // emit a fallback diagnostic if not. + FallbackDiagnostic diag(solution, getLocator()); + return diag.diagnose(asNote); } IgnoreInvalidASTNode *IgnoreInvalidASTNode::create(ConstraintSystem &cs, diff --git a/lib/Sema/CSSolver.cpp b/lib/Sema/CSSolver.cpp index 2f6d0c5f0100d..9f8e339586b2e 100644 --- a/lib/Sema/CSSolver.cpp +++ b/lib/Sema/CSSolver.cpp @@ -1457,7 +1457,7 @@ ConstraintSystem::solve(SyntacticElementTarget &target, } case SolutionResult::Error: - maybeProduceFallbackDiagnostic(target); + maybeProduceFallbackDiagnostic(target.getLoc()); return std::nullopt; case SolutionResult::TooComplex: { diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 5aaa0a75685f0..c4d479a346e32 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -4875,8 +4875,7 @@ bool ConstraintSystem::isConformanceUnavailable(ProtocolConformanceRef conforman /// If we aren't certain that we've emitted a diagnostic, emit a fallback /// diagnostic. -void ConstraintSystem::maybeProduceFallbackDiagnostic( - SyntacticElementTarget target) const { +void ConstraintSystem::maybeProduceFallbackDiagnostic(SourceLoc loc) const { if (Options.contains(ConstraintSystemFlags::SuppressDiagnostics)) return; @@ -4888,7 +4887,7 @@ void ConstraintSystem::maybeProduceFallbackDiagnostic( (diagnosticTransaction && diagnosticTransaction->hasErrors())) return; - ctx.Diags.diagnose(target.getLoc(), diag::failed_to_produce_diagnostic); + ctx.Diags.diagnose(loc, diag::failed_to_produce_diagnostic); } SourceLoc constraints::getLoc(ASTNode anchor) { diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 5cc47ab8d8332..640090ccceadd 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -2637,10 +2637,12 @@ static Type evaluateTypeResolution(const TypeResolution *resolution, TypeResolver(*resolution, silContext) .resolveType(TyR, resolution->getOptions()); - // If we resolved down to an error, make sure to mark the typeRepr as invalid - // so we don't produce a redundant diagnostic. + // If we resolved down to an error, and we haven't silenced diagnostics, make + // sure to mark the typeRepr as invalid so we don't produce a redundant + // diagnostic. if (result->hasError()) { - TyR->setInvalid(); + if (!options.contains(TypeResolutionFlags::SilenceErrors)) + TyR->setInvalid(); return result; } diff --git a/test/Constraints/patterns.swift b/test/Constraints/patterns.swift index 5be028f7eb08e..ee35b0e647f0d 100644 --- a/test/Constraints/patterns.swift +++ b/test/Constraints/patterns.swift @@ -820,3 +820,17 @@ do { } } } + +// Make sure we diagnose 'Undefined' here. +func testUndefinedTypeInPattern(_ x: Int) { + switch x { + case Optional.alsoUndefined: // expected-error {{cannot find type 'Undefined' in scope}} + break + } + _ = { + switch x { + case Optional.alsoUndefined: // expected-error {{cannot find type 'Undefined' in scope}} + break + } + } +} diff --git a/validation-test/compiler_crashers_2/75d8fd688b445bb.swift b/validation-test/compiler_crashers_2_fixed/75d8fd688b445bb.swift similarity index 87% rename from validation-test/compiler_crashers_2/75d8fd688b445bb.swift rename to validation-test/compiler_crashers_2_fixed/75d8fd688b445bb.swift index 570f5167e4721..22394f1471878 100644 --- a/validation-test/compiler_crashers_2/75d8fd688b445bb.swift +++ b/validation-test/compiler_crashers_2_fixed/75d8fd688b445bb.swift @@ -1,5 +1,5 @@ // {"kind":"typecheck","original":"b7a10f72","signature":"(anonymous namespace)::Verifier::walkToExprPre(swift::Expr*)","signatureAssert":"Assertion failed: ((HadError || !isa(M) || cast(M)->ASTStage < SourceFile::TypeChecked) && \"OverloadedDeclRef\" \"in wrong phase\"), function walkToExprPre"} -// RUN: not --crash %target-swift-frontend -typecheck %s +// RUN: not %target-swift-frontend -typecheck %s func a(b : Int) { _ = { switch b {