From bf124b8a4a24d14f8a5bb01300f379583966495d Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 31 Jan 2020 17:55:15 -0800 Subject: [PATCH 1/2] [Type checker] Use typeCheckCondition() rather than fake it. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Type checking an expression pattern had a hack to work around some diagnostics issues with conditions. These issues have been addressed by the new diagnostic infrastructure, so remove this unnecessary use of ExprTypeCheckListener and check the expression pattern condition using… typeCheckCondition(). --- lib/Sema/TypeCheckConstraints.cpp | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 0a9f90509187a..1a5e16abeff3f 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -3209,30 +3209,7 @@ bool TypeChecker::typeCheckExprPattern(ExprPattern *EP, DeclContext *DC, /*Implicit=*/true); // Check the expression as a condition. - // - // TODO: Type-check of `~=` operator can't (yet) use `typeCheckCondition` - // because that utilizes contextual type which interferes with diagnostics. - // We don't yet have a full access to pattern-matching context in - // constraint system, which is required to enable these situations - // to be properly diagnosed. - struct ConditionListener : public ExprTypeCheckListener { - // Add the appropriate Boolean constraint. - bool builtConstraints(ConstraintSystem &cs, Expr *expr) override { - // Otherwise, the result must be convertible to Bool. - auto boolDecl = cs.getASTContext().getBoolDecl(); - if (!boolDecl) - return true; - - // Condition must convert to Bool. - cs.addConstraint(ConstraintKind::Conversion, cs.getType(expr), - boolDecl->getDeclaredType(), - cs.getConstraintLocator(expr)); - return false; - } - }; - - ConditionListener listener; - bool hadError = !typeCheckExpression(matchCall, DC, &listener); + bool hadError = typeCheckCondition(matchCall, DC); // Save the type-checked expression in the pattern. EP->setMatchExpr(matchCall); // Set the type on the pattern. From 4b0e7b27808247e63be70c8f46abf71e4583cc19 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 31 Jan 2020 18:20:46 -0800 Subject: [PATCH 2/2] [Type checker] Sink logic for @autoclosure default parameters into the solver Rather than use an ExprTypeCheckListener subclass to introduce the autoclosure expression, do it at the end of solving. --- lib/Sema/CSDiagnostics.cpp | 3 +++ lib/Sema/CSSimplify.cpp | 1 + lib/Sema/TypeCheckConstraints.cpp | 44 +++++++++++++------------------ lib/Sema/TypeChecker.h | 4 +++ 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index b85e37691bb76..c0ff3daf3f172 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -560,6 +560,7 @@ Optional> GenericArgumentsMismatchFailure::getDiagnosticFor( case CTP_ReturnSingleExpr: return diag::cannot_convert_to_return_type; case CTP_DefaultParameter: + case CTP_AutoclosureDefaultParameter: return diag::cannot_convert_default_arg_value; case CTP_YieldByValue: return diag::cannot_convert_yield_value; @@ -2085,6 +2086,7 @@ getContextualNilDiagnostic(ContextualTypePurpose CTP) { case CTP_EnumCaseRawValue: return diag::cannot_convert_raw_initializer_value_nil; case CTP_DefaultParameter: + case CTP_AutoclosureDefaultParameter: return diag::cannot_convert_default_arg_value_nil; case CTP_YieldByValue: return diag::cannot_convert_yield_value_nil; @@ -2863,6 +2865,7 @@ ContextualFailure::getDiagnosticFor(ContextualTypePurpose context, case CTP_EnumCaseRawValue: return diag::cannot_convert_raw_initializer_value; case CTP_DefaultParameter: + case CTP_AutoclosureDefaultParameter: return forProtocol ? diag::cannot_convert_default_arg_value_protocol : diag::cannot_convert_default_arg_value; case CTP_YieldByValue: diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 09a1c7eda4973..e017aeb2cee63 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -9130,6 +9130,7 @@ void ConstraintSystem::addContextualConversionConstraint( case CTP_ThrowStmt: case CTP_EnumCaseRawValue: case CTP_DefaultParameter: + case CTP_AutoclosureDefaultParameter: case CTP_ClosureResult: case CTP_DictionaryKey: case CTP_DictionaryValue: diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 1a5e16abeff3f..d1ca555020aea 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -2107,6 +2107,14 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc, } } + // For an @autoclosure default parameter, we want to convert to the result + // type. Stash the autoclosure default parameter type. + FunctionType *autoclosureDefaultParamType = nullptr; + if (convertTypePurpose == CTP_AutoclosureDefaultParameter) { + autoclosureDefaultParamType = convertType.getType()->castTo(); + convertType.setType(autoclosureDefaultParamType->getResult()); + } + // Tell the constraint system what the contextual type is. This informs // diagnostics and is a hint for various performance optimizations. // FIXME: Look through LoadExpr. This is an egregious hack due to the @@ -2130,6 +2138,7 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc, allowFreeTypeVariables = FreeTypeVariableBinding::UnresolvedType; Type convertTo = convertType.getType(); + if (options.contains(TypeCheckExprFlags::ExpressionTypeMustBeOptional)) { assert(!convertTo && "convertType and type check options conflict"); auto *convertTypeLocator = @@ -2175,6 +2184,12 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc, } result = resultTarget->getAsExpr(); + // For an @autoclosure default parameter type, add the autoclosure + // conversion. + if (convertTypePurpose == CTP_AutoclosureDefaultParameter) { + result = cs.buildAutoClosureExpr(result, autoclosureDefaultParamType); + } + // Notify listener that we've applied the solution. if (listener) result = listener->appliedSolution(solution, result); @@ -2204,32 +2219,9 @@ Type TypeChecker::typeCheckParameterDefault(Expr *&defaultValue, DeclContext *DC, Type paramType, bool isAutoClosure) { assert(paramType && !paramType->hasError()); - - if (isAutoClosure) { - class AutoClosureListener : public ExprTypeCheckListener { - FunctionType *ParamType; - - public: - AutoClosureListener(FunctionType *paramType) - : ParamType(paramType) {} - - Expr *appliedSolution(constraints::Solution &solution, - Expr *expr) override { - auto &cs = solution.getConstraintSystem(); - return cs.buildAutoClosureExpr(expr, ParamType); - } - }; - - auto *fnType = paramType->castTo(); - AutoClosureListener listener(fnType); - return typeCheckExpression(defaultValue, DC, - TypeLoc::withoutLoc(fnType->getResult()), - CTP_DefaultParameter, TypeCheckExprOptions(), - &listener); - } - - return typeCheckExpression(defaultValue, DC, TypeLoc::withoutLoc(paramType), - CTP_DefaultParameter); + return typeCheckExpression( + defaultValue, DC, TypeLoc::withoutLoc(paramType), + isAutoClosure ? CTP_AutoclosureDefaultParameter : CTP_DefaultParameter); } Type TypeChecker:: diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 3c643d706e25e..341f00a9b0e63 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -133,6 +133,10 @@ enum ContextualTypePurpose { CTP_EnumCaseRawValue, ///< Raw value specified for "case X = 42" in enum. CTP_DefaultParameter, ///< Default value in parameter 'foo(a : Int = 42)'. + /// Default value in @autoclosure parameter + /// 'foo(a : @autoclosure () -> Int = 42)'. + CTP_AutoclosureDefaultParameter, + CTP_CalleeResult, ///< Constraint is placed on the result of a callee. CTP_CallArgument, ///< Call to function or operator requires type. CTP_ClosureResult, ///< Closure result expects a specific type.