diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 0891e23c6474c..f4dff643717aa 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2062,48 +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, nullptr); - }; - - Type resultTy; - auto *resultLoc = - CS.getConstraintLocator(closure, ConstraintLocator::ClosureResult); - 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( - resultLoc, - 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); } 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] +}