29
29
#include " swift/AST/NameLookup.h"
30
30
#include " swift/AST/ParameterList.h"
31
31
#include " swift/AST/PrettyStackTrace.h"
32
+ #include " swift/AST/ProtocolConformance.h"
32
33
#include " swift/AST/SubstitutionMap.h"
33
34
#include " swift/AST/TypeCheckerDebugConsumer.h"
34
35
#include " swift/Basic/Statistic.h"
@@ -1914,6 +1915,11 @@ Expr *ExprTypeCheckListener::appliedSolution(Solution &solution, Expr *expr) {
1914
1915
return expr;
1915
1916
}
1916
1917
1918
+ void ExprTypeCheckListener::preCheckFailed (Expr *expr) {}
1919
+ void ExprTypeCheckListener::constraintGenerationFailed (Expr *expr) {}
1920
+ void ExprTypeCheckListener::applySolutionFailed (Solution &solution,
1921
+ Expr *expr) {}
1922
+
1917
1923
void ParentConditionalConformance::diagnoseConformanceStack (
1918
1924
DiagnosticEngine &diags, SourceLoc loc,
1919
1925
ArrayRef<ParentConditionalConformance> conformances) {
@@ -1941,20 +1947,116 @@ bool GenericRequirementsCheckListener::diagnoseUnsatisfiedRequirement(
1941
1947
return false ;
1942
1948
}
1943
1949
1950
+ // / Sometimes constraint solver fails without producing any diagnostics,
1951
+ // / that leads to crashes down the line in AST Verifier or SILGen
1952
+ // / which, as a result, are much harder to figure out.
1953
+ // /
1954
+ // / This class is intended to guard against situations like that by
1955
+ // / keeping track of failures of different type-check phases, and
1956
+ // / emitting fallback fatal error if any of them fail without producing
1957
+ // / error diagnostic, and there were no errors emitted or scheduled to be
1958
+ // / emitted previously.
1959
+ class FallbackDiagnosticListener : public ExprTypeCheckListener {
1960
+ TypeChecker &TC;
1961
+ TypeCheckExprOptions Options;
1962
+ ExprTypeCheckListener *BaseListener;
1963
+
1964
+ public:
1965
+ FallbackDiagnosticListener (TypeChecker &TC, TypeCheckExprOptions options,
1966
+ ExprTypeCheckListener *base)
1967
+ : TC(TC), Options(options), BaseListener(base) {}
1968
+
1969
+ bool builtConstraints (ConstraintSystem &cs, Expr *expr) override {
1970
+ return BaseListener ? BaseListener->builtConstraints (cs, expr) : false ;
1971
+ }
1972
+
1973
+ Expr *foundSolution (Solution &solution, Expr *expr) override {
1974
+ return BaseListener ? BaseListener->foundSolution (solution, expr) : expr;
1975
+ }
1976
+
1977
+ Expr *appliedSolution (Solution &solution, Expr *expr) override {
1978
+ return BaseListener ? BaseListener->appliedSolution (solution, expr) : expr;
1979
+ }
1980
+
1981
+ void preCheckFailed (Expr *expr) override {
1982
+ if (BaseListener)
1983
+ BaseListener->preCheckFailed (expr);
1984
+ maybeProduceFallbackDiagnostic (expr);
1985
+ }
1986
+
1987
+ void constraintGenerationFailed (Expr *expr) override {
1988
+ if (BaseListener)
1989
+ BaseListener->constraintGenerationFailed (expr);
1990
+ maybeProduceFallbackDiagnostic (expr);
1991
+ }
1992
+
1993
+ void applySolutionFailed (Solution &solution, Expr *expr) override {
1994
+ if (BaseListener)
1995
+ BaseListener->applySolutionFailed (solution, expr);
1996
+
1997
+ if (hadAnyErrors ())
1998
+ return ;
1999
+
2000
+ // If solution involves invalid or incomplete conformances that's
2001
+ // a probable cause of failure to apply it without producing an error,
2002
+ // which is going to be diagnosed later, so let's not produce
2003
+ // fallback diagnostic in this case.
2004
+ if (llvm::any_of (
2005
+ solution.Conformances ,
2006
+ [](const std::pair<ConstraintLocator *, ProtocolConformanceRef>
2007
+ &conformance) -> bool {
2008
+ auto &ref = conformance.second ;
2009
+ return ref.isConcrete () && (ref.getConcrete ()->isInvalid () ||
2010
+ ref.getConcrete ()->isIncomplete ());
2011
+ }))
2012
+ return ;
2013
+
2014
+ maybeProduceFallbackDiagnostic (expr);
2015
+ }
2016
+
2017
+ private:
2018
+ bool hadAnyErrors () const { return TC.Context .Diags .hadAnyError (); }
2019
+
2020
+ void maybeProduceFallbackDiagnostic (Expr *expr) const {
2021
+ if (Options.contains (TypeCheckExprFlags::SubExpressionDiagnostics) ||
2022
+ Options.contains (TypeCheckExprFlags::SuppressDiagnostics))
2023
+ return ;
2024
+
2025
+ // Before producing fatal error here, let's check if there are any "error"
2026
+ // diagnostics already emitted or waiting to be emitted. Because they are
2027
+ // a better indication of the problem.
2028
+ if (!(hadAnyErrors () || TC.Context .hasDelayedConformanceErrors ()))
2029
+ TC.diagnose (expr->getLoc (), diag::failed_to_produce_diagnostic);
2030
+ }
2031
+ };
2032
+
1944
2033
#pragma mark High-level entry points
1945
2034
Type TypeChecker::typeCheckExpression (Expr *&expr, DeclContext *dc,
1946
2035
TypeLoc convertType,
1947
2036
ContextualTypePurpose convertTypePurpose,
1948
2037
TypeCheckExprOptions options,
1949
2038
ExprTypeCheckListener *listener,
1950
2039
ConstraintSystem *baseCS) {
2040
+ FallbackDiagnosticListener diagListener (*this , options, listener);
2041
+ return typeCheckExpressionImpl (expr, dc, convertType, convertTypePurpose,
2042
+ options, diagListener, baseCS);
2043
+ }
2044
+
2045
+ Type TypeChecker::typeCheckExpressionImpl (Expr *&expr, DeclContext *dc,
2046
+ TypeLoc convertType,
2047
+ ContextualTypePurpose convertTypePurpose,
2048
+ TypeCheckExprOptions options,
2049
+ ExprTypeCheckListener &listener,
2050
+ ConstraintSystem *baseCS) {
1951
2051
FrontendStatsTracer StatsTracer (Context.Stats , " typecheck-expr" , expr);
1952
2052
PrettyStackTraceExpr stackTrace (Context, " type-checking" , expr);
1953
2053
1954
2054
// First, pre-check the expression, validating any types that occur in the
1955
2055
// expression and folding sequence expressions.
1956
- if (preCheckExpression (expr, dc))
2056
+ if (preCheckExpression (expr, dc)) {
2057
+ listener.preCheckFailed (expr);
1957
2058
return Type ();
2059
+ }
1958
2060
1959
2061
// Construct a constraint system from this expression.
1960
2062
ConstraintSystemOptions csOptions = ConstraintSystemFlags::AllowFixes;
@@ -2009,10 +2111,9 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
2009
2111
convertTo = getOptionalType (expr->getLoc (), var);
2010
2112
}
2011
2113
2012
- // Attempt to solve the constraint system.
2013
2114
SmallVector<Solution, 4 > viable;
2014
- if (cs. solve (expr, convertTo, listener, viable,
2015
- allowFreeTypeVariables))
2115
+ // Attempt to solve the constraint system.
2116
+ if (cs. solve (expr, convertTo, &listener, viable, allowFreeTypeVariables))
2016
2117
return Type ();
2017
2118
2018
2119
// If the client allows the solution to have unresolved type expressions,
@@ -2026,29 +2127,26 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
2026
2127
2027
2128
auto result = expr;
2028
2129
auto &solution = viable[0 ];
2029
- if (listener) {
2030
- result = listener->foundSolution (solution, result);
2031
- if (!result)
2032
- return Type ();
2033
- }
2130
+ result = listener.foundSolution (solution, result);
2131
+ if (!result)
2132
+ return Type ();
2034
2133
2035
2134
// Apply the solution to the expression.
2036
2135
result = cs.applySolution (
2037
2136
solution, result, convertType.getType (),
2038
2137
options.contains (TypeCheckExprFlags::IsDiscarded),
2039
2138
options.contains (TypeCheckExprFlags::SkipMultiStmtClosures));
2139
+
2040
2140
if (!result) {
2141
+ listener.applySolutionFailed (solution, expr);
2041
2142
// Failure already diagnosed, above, as part of applying the solution.
2042
2143
return Type ();
2043
2144
}
2044
2145
2045
- // If there's a listener, notify it that we've applied the solution.
2046
- if (listener) {
2047
- result = listener->appliedSolution (solution, result);
2048
- if (!result) {
2049
- return Type ();
2050
- }
2051
- }
2146
+ // Notify listener that we've applied the solution.
2147
+ result = listener.appliedSolution (solution, result);
2148
+ if (!result)
2149
+ return Type ();
2052
2150
2053
2151
if (getLangOpts ().DebugConstraintSolver ) {
2054
2152
auto &log = Context.TypeCheckerDebug ->getStream ();
0 commit comments