From 80560dab2582172e0684080382586591a55cb342 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Thu, 27 Aug 2020 22:17:09 +0300 Subject: [PATCH 1/2] CSGen: Infer generic arguments in explicit closure result types --- lib/Sema/CSGen.cpp | 14 +++++++++----- test/Constraints/closures.swift | 12 ++++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 0891e23c6474c..37bc51c12508b 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2073,12 +2073,14 @@ namespace { return resolveTypeReferenceInExpression( closure->getExplicitResultTypeRepr(), - TypeResolverContext::InExpression, nullptr); + TypeResolverContext::InExpression, + // Introduce type variables for unbound generics. + OpenUnboundGenericType( + CS, CS.getConstraintLocator(closure, + ConstraintLocator::ClosureResult))); }; Type resultTy; - auto *resultLoc = - CS.getConstraintLocator(closure, ConstraintLocator::ClosureResult); if (auto explicityTy = getExplicitResultType()) { resultTy = explicityTy; } else { @@ -2099,9 +2101,11 @@ namespace { // If this is a multi-statement closure, let's mark result // as potential hole right away. resultTy = CS.createTypeVariable( - resultLoc, + CS.getConstraintLocator(closure, + ConstraintLocator::ClosureResult), shouldTypeCheckInEnclosingExpression(closure) - ? 0 : TVO_CanBindToHole); + ? 0 + : TVO_CanBindToHole); } } diff --git a/test/Constraints/closures.swift b/test/Constraints/closures.swift index b6f99b7350729..0b77ce6ac87b2 100644 --- a/test/Constraints/closures.swift +++ b/test/Constraints/closures.swift @@ -1030,3 +1030,15 @@ func sr12815() { .doesntExist2() { $0 } } } + +// Make sure we can infer generic arguments in an explicit result type. +let explicitUnboundResult1 = { () -> Array in [0] } +let explicitUnboundResult2: (Array) -> Array = { + (arr: Array) -> Array in [0] +} +// FIXME: Should we prioritize the contextual result type and infer Array +// rather than using a type variable in these cases? +// expected-error@+1 {{unable to infer closure type in the current context}} +let explicitUnboundResult3: (Array) -> Array = { + (arr: Array) -> Array in [true] +} From 61d86d5fd2652103cb09d6b2fe7dcb48c3696104 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Thu, 27 Aug 2020 22:23:19 +0300 Subject: [PATCH 2/2] [NFC] CSGen: Clean up some flow in inferClosureType --- lib/Sema/CSGen.cpp | 70 +++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 42 deletions(-) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 37bc51c12508b..f4dff643717aa 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2062,52 +2062,38 @@ namespace { // parameter or return type is omitted, a fresh type variable is used to // stand in for that parameter or return type, allowing it to be inferred // from context. - auto getExplicitResultType = [&]() -> Type { - if (!closure->hasExplicitResultType()) { - return Type(); - } + Type resultTy = [&] { + if (closure->hasExplicitResultType()) { + if (auto declaredTy = closure->getExplicitResultType()) { + return declaredTy; + } - if (auto declaredTy = closure->getExplicitResultType()) { - return declaredTy; + const auto resolvedTy = resolveTypeReferenceInExpression( + closure->getExplicitResultTypeRepr(), + TypeResolverContext::InExpression, + // Introduce type variables for unbound generics. + OpenUnboundGenericType( + CS, CS.getConstraintLocator( + closure, ConstraintLocator::ClosureResult))); + if (resolvedTy) + return resolvedTy; } - return resolveTypeReferenceInExpression( - closure->getExplicitResultTypeRepr(), - TypeResolverContext::InExpression, - // Introduce type variables for unbound generics. - OpenUnboundGenericType( - CS, CS.getConstraintLocator(closure, - ConstraintLocator::ClosureResult))); - }; - - Type resultTy; - if (auto explicityTy = getExplicitResultType()) { - resultTy = explicityTy; - } else { - auto getContextualResultType = [&]() -> Type { - if (auto contextualType = CS.getContextualType(closure)) { - if (auto fnType = contextualType->getAs()) - return fnType->getResult(); - } - return Type(); - }; - - if (auto contextualResultTy = getContextualResultType()) { - resultTy = contextualResultTy; - } else { - // If no return type was specified, create a fresh type - // variable for it and mark it as possible hole. - // - // If this is a multi-statement closure, let's mark result - // as potential hole right away. - resultTy = CS.createTypeVariable( - CS.getConstraintLocator(closure, - ConstraintLocator::ClosureResult), - shouldTypeCheckInEnclosingExpression(closure) - ? 0 - : TVO_CanBindToHole); + if (auto contextualType = CS.getContextualType(closure)) { + if (auto fnType = contextualType->getAs()) + return fnType->getResult(); } - } + + // If no return type was specified, create a fresh type + // variable for it and mark it as possible hole. + // + // If this is a multi-statement closure, let's mark result + // as potential hole right away. + return Type(CS.createTypeVariable( + CS.getConstraintLocator(closure, ConstraintLocator::ClosureResult), + shouldTypeCheckInEnclosingExpression(closure) ? 0 + : TVO_CanBindToHole)); + }(); return FunctionType::get(closureParams, resultTy, extInfo); }