Compute return type for property getters more safely

Do not call `isError()` on property's type right after creation of
PropertyGetterDescriptor because the property has no getter yet (it's created
but not yet stored to the property, that happens a bit later), and `isError()`
leads to computation of the delegate type, which for delegated properties
performs some complex resolution (see `VariableTypeResolver#process`) which
relies on the fact that the property already has a getter.

Since the purpose of the original change (883e2e4d) was to support a quick fix
which would add the type to a property in an expression like "val x get() =
...", check the type (or initializer) presence in the PSI instead, this is
safer and is still suitable for the quick fix.

Also fix arguments to "wrong getter type" diagnostic: previously something
useless like "expected Int, actual Int" was reported

 #KT-11809 Fixed
This commit is contained in:
Alexander Udalov
2016-04-07 12:22:14 +03:00
parent f1b061d662
commit 7c90fbe4de
5 changed files with 64 additions and 15 deletions
@@ -897,16 +897,6 @@ public class DescriptorResolver {
annotationSplitter.getAnnotationsForTarget(PROPERTY_GETTER),
annotationResolver.resolveAnnotationsWithoutArguments(scopeWithTypeParameters, getter.getModifierList(), trace)));
KotlinType outType = propertyDescriptor.getType();
KotlinType returnType = outType;
KtTypeReference returnTypeReference = getter.getReturnTypeReference();
if (returnTypeReference != null) {
returnType = typeResolver.resolveType(scopeWithTypeParameters, returnTypeReference, trace, true);
if (!TypeUtils.equalTypes(returnType, outType)) {
trace.report(WRONG_GETTER_RETURN_TYPE.on(returnTypeReference, propertyDescriptor.getReturnType(), outType));
}
}
getterDescriptor = new PropertyGetterDescriptorImpl(
propertyDescriptor, getterAnnotations,
resolveModalityFromModifiers(getter, propertyDescriptor.getModality()),
@@ -914,10 +904,8 @@ public class DescriptorResolver {
/* isDefault = */ false, getter.hasModifier(EXTERNAL_KEYWORD),
CallableMemberDescriptor.Kind.DECLARATION, null, KotlinSourceElementKt.toSourceElement(getter)
);
if (returnType.isError() && !getter.hasBlockBody() && getter.hasBody()) {
returnType = inferReturnTypeFromExpressionBody(storageManager, expressionTypingServices, trace, scopeWithTypeParameters,
DataFlowInfoFactory.EMPTY, getter, getterDescriptor);
}
KotlinType returnType =
determineGetterReturnType(scopeWithTypeParameters, trace, getterDescriptor, getter, propertyDescriptor.getType());
getterDescriptor.initialize(returnType);
trace.record(BindingContext.PROPERTY_ACCESSOR, getter, getterDescriptor);
}
@@ -930,6 +918,37 @@ public class DescriptorResolver {
return getterDescriptor;
}
@NotNull
private KotlinType determineGetterReturnType(
@NotNull LexicalScope scope,
@NotNull BindingTrace trace,
@NotNull PropertyGetterDescriptor getterDescriptor,
@NotNull KtPropertyAccessor getter,
@NotNull KotlinType propertyType
) {
KtTypeReference returnTypeReference = getter.getReturnTypeReference();
if (returnTypeReference != null) {
KotlinType explicitReturnType = typeResolver.resolveType(scope, returnTypeReference, trace, true);
if (!TypeUtils.equalTypes(explicitReturnType, propertyType)) {
trace.report(WRONG_GETTER_RETURN_TYPE.on(returnTypeReference, propertyType, explicitReturnType));
}
return explicitReturnType;
}
// If a property has no type specified in the PSI but the getter does (or has an initializer e.g. "val x get() = ..."),
// infer the correct type for the getter but leave the error type for the property.
// This is useful for an IDE quick fix which would add the type to the property
KtProperty property = getter.getProperty();
if (!property.hasDelegateExpressionOrInitializer() && property.getTypeReference() == null &&
getter.hasBody() && !getter.hasBlockBody()) {
return inferReturnTypeFromExpressionBody(
storageManager, expressionTypingServices, trace, scope, DataFlowInfoFactory.EMPTY, getter, getterDescriptor
);
}
return propertyType;
}
@NotNull
/*package*/ static DeferredType inferReturnTypeFromExpressionBody(
@NotNull StorageManager storageManager,