Approximate anonymous return types for private inline functions to explicit supertype or Any (KT-33917)

This commit is contained in:
Victor Petukhov
2020-09-25 16:11:27 +03:00
committed by Dmitriy Novozhilov
parent 670f029bdf
commit ba44ad1aa3
14 changed files with 276 additions and 28 deletions
@@ -1027,8 +1027,7 @@ public class DefaultErrorMessages {
MAP.put(PROTECTED_CALL_FROM_PUBLIC_INLINE_ERROR, "Protected function call from public-API inline function is prohibited", NAME);
MAP.put(INVALID_DEFAULT_FUNCTIONAL_PARAMETER_FOR_INLINE, "Invalid default value for inline parameter: ''{0}''. Only lambdas, anonymous functions, and callable references are supported", ELEMENT_TEXT, SHORT_NAMES_IN_TYPES);
MAP.put(NOT_SUPPORTED_INLINE_PARAMETER_IN_INLINE_PARAMETER_DEFAULT_VALUE, "Usage of inline parameter ''{0}'' in default value for another inline parameter is not supported", ELEMENT_TEXT, SHORT_NAMES_IN_TYPES);
MAP.put(PRIVATE_INLINE_FUNCTIONS_RETURNING_ANONYMOUS_OBJECTS, "Return type of the private inline function can't be anonymous. It will be approximated to Any in 1.5." +
"See https://youtrack.jetbrains.com/issue/KT-33917 for more details");
MAP.put(PRIVATE_INLINE_FUNCTIONS_RETURNING_ANONYMOUS_OBJECTS, "Return type of the private inline function can't be anonymous. It will be approximated to Any in a future release. See KT-33917 for more details");
//Inline non locals
MAP.put(NON_LOCAL_RETURN_NOT_ALLOWED, "Can''t inline ''{0}'' here: it may contain non-local returns. Add ''crossinline'' modifier to parameter declaration ''{0}''", ELEMENT_TEXT);
MAP.put(INLINE_CALL_CYCLE, "The ''{0}'' invocation is a part of inline cycle", NAME);
@@ -1024,7 +1024,8 @@ public class DescriptorResolver {
@NotNull KtDeclaration declaration,
@NotNull KotlinType type,
@NotNull BindingTrace trace,
@NotNull Iterable<DeclarationSignatureAnonymousTypeTransformer> anonymousTypeTransformers
@NotNull Iterable<DeclarationSignatureAnonymousTypeTransformer> anonymousTypeTransformers,
@NotNull LanguageVersionSettings languageVersionSettings
) {
for (DeclarationSignatureAnonymousTypeTransformer transformer : anonymousTypeTransformers) {
KotlinType transformedType = transformer.transformAnonymousType(descriptor, type);
@@ -1038,7 +1039,12 @@ public class DescriptorResolver {
return type;
}
if (!DescriptorVisibilities.isPrivate(descriptor.getVisibility())) {
boolean isPrivate = DescriptorVisibilities.isPrivate(descriptor.getVisibility());
boolean isInlineFunction = descriptor instanceof SimpleFunctionDescriptor && ((SimpleFunctionDescriptor) descriptor).isInline();
boolean isAnonymousReturnTypesInPrivateInlineFunctionsForbidden =
languageVersionSettings.supportsFeature(LanguageFeature.ApproximateAnonymousReturnTypesInPrivateInlineFunctions);
if (!isPrivate || (isInlineFunction && isAnonymousReturnTypesInPrivateInlineFunctionsForbidden)) {
if (type.getConstructor().getSupertypes().size() == 1) {
return type.getConstructor().getSupertypes().iterator().next();
}
@@ -1221,7 +1227,9 @@ public class DescriptorResolver {
return wrappedTypeFactory.createRecursionIntolerantDeferredType(trace, () -> {
PreliminaryDeclarationVisitor.Companion.createForDeclaration(function, trace, languageVersionSettings);
KotlinType type = expressionTypingServices.getBodyExpressionType(trace, scope, dataFlowInfo, function, functionDescriptor);
KotlinType publicType = transformAnonymousTypeIfNeeded(functionDescriptor, function, type, trace, anonymousTypeTransformers);
KotlinType publicType = transformAnonymousTypeIfNeeded(
functionDescriptor, function, type, trace, anonymousTypeTransformers, languageVersionSettings
);
UnwrappedType approximatedType = typeApproximator.approximateDeclarationType(publicType, false, languageVersionSettings);
KotlinType sanitizedType = declarationReturnTypeSanitizer.sanitizeReturnType(approximatedType, wrappedTypeFactory, trace, languageVersionSettings);
functionsTypingVisitor.checkTypesForReturnStatements(function, trace, sanitizedType);
@@ -91,7 +91,9 @@ class VariableTypeAndInitializerResolver(
val initializerType = resolveInitializerType(
scopeForInitializer, variable.initializer!!, dataFlowInfo, inferenceSession, trace, local
)
transformAnonymousTypeIfNeeded(variableDescriptor, variable, initializerType, trace, anonymousTypeTransformers)
transformAnonymousTypeIfNeeded(
variableDescriptor, variable, initializerType, trace, anonymousTypeTransformers, languageVersionSettings
)
}
else -> resolveInitializerType(scopeForInitializer, variable.initializer!!, dataFlowInfo, inferenceSession, trace, local)
@@ -157,7 +159,9 @@ class VariableTypeAndInitializerResolver(
val delegatedType = getterReturnType?.let { approximateType(it, local) }
?: ErrorUtils.createErrorType("Type from delegate")
transformAnonymousTypeIfNeeded(variableDescriptor, property, delegatedType, trace, anonymousTypeTransformers)
transformAnonymousTypeIfNeeded(
variableDescriptor, property, delegatedType, trace, anonymousTypeTransformers, languageVersionSettings
)
}
private fun resolveInitializerType(
@@ -10,16 +10,15 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.psiUtil.isPrivate
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
object PrivateInlineFunctionsReturningAnonymousObjectsChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
if (context.languageVersionSettings.supportsFeature(LanguageFeature.ForbidAnonymousReturnTypesInPrivateInlineFunctions))
if (context.languageVersionSettings.supportsFeature(LanguageFeature.ApproximateAnonymousReturnTypesInPrivateInlineFunctions))
return
if (descriptor !is SimpleFunctionDescriptor || !descriptor.isInline || !declaration.isPrivate() || declaration !is KtNamedFunction)
if (descriptor !is SimpleFunctionDescriptor || !descriptor.isInline || !DescriptorVisibilities.isPrivate(descriptor.visibility) || declaration !is KtNamedFunction)
return
val returnTypeConstructor = descriptor.returnType?.constructor ?: return