Support platform/impl modifiers for properties

Do not allow platform properties to have backing fields, initializers, be
delegated, lateinit or const, or have accessors with bodies
This commit is contained in:
Alexander Udalov
2016-11-01 18:54:00 +03:00
parent af1264a46d
commit ce9691cd2b
23 changed files with 206 additions and 58 deletions
@@ -494,6 +494,8 @@ public interface Errors {
DiagnosticFactory0<KtDeclaration> PLATFORM_DECLARATION_WITH_BODY = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
DiagnosticFactory0<KtParameter> PLATFORM_DECLARATION_WITH_DEFAULT_PARAMETER = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtExpression> PLATFORM_PROPERTY_INITIALIZER = DiagnosticFactory0.create(ERROR);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Errors/warnings inside code blocks
@@ -260,6 +260,8 @@ public class DefaultErrorMessages {
MAP.put(PLATFORM_DECLARATION_WITH_BODY, "Platform declaration must not have a body");
MAP.put(PLATFORM_DECLARATION_WITH_DEFAULT_PARAMETER, "Platform declaration cannot have parameters with default values");
MAP.put(PLATFORM_PROPERTY_INITIALIZER, "Platform property cannot have an initializer");
MAP.put(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT, "Projections are not allowed on type arguments of functions and properties");
MAP.put(SUPERTYPE_NOT_INITIALIZED, "This type has a constructor, and thus must be initialized here");
MAP.put(NOTHING_TO_OVERRIDE, "''{0}'' overrides nothing", NAME);
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.resolve
import com.google.common.collect.ImmutableSet
import com.google.common.collect.Sets
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageVersionSettings
@@ -650,17 +649,19 @@ class DeclarationsChecker(
val initializer = property.initializer
val delegate = property.delegate
val isPlatform = propertyDescriptor.isPlatform
if (initializer != null) {
if (inTrait) {
trace.report(PROPERTY_INITIALIZER_IN_INTERFACE.on(initializer))
}
else {
if (!backingFieldRequired) {
trace.report(PROPERTY_INITIALIZER_NO_BACKING_FIELD.on(initializer))
}
else if (property.receiverTypeReference != null) {
trace.report(EXTENSION_PROPERTY_WITH_BACKING_FIELD.on(initializer))
}
else if (isPlatform) {
trace.report(PLATFORM_PROPERTY_INITIALIZER.on(initializer))
}
else if (!backingFieldRequired) {
trace.report(PROPERTY_INITIALIZER_NO_BACKING_FIELD.on(initializer))
}
else if (property.receiverTypeReference != null) {
trace.report(EXTENSION_PROPERTY_WITH_BACKING_FIELD.on(initializer))
}
}
else if (delegate != null) {
@@ -670,7 +671,7 @@ class DeclarationsChecker(
}
else {
val isUninitialized = trace.bindingContext.get(BindingContext.IS_UNINITIALIZED, propertyDescriptor) ?: false
if (backingFieldRequired && !inTrait && !propertyDescriptor.isLateInit && isUninitialized) {
if (backingFieldRequired && !inTrait && !propertyDescriptor.isLateInit && !isPlatform && isUninitialized) {
if (containingDeclaration !is ClassDescriptor || hasAccessorImplementation) {
trace.report(MUST_BE_INITIALIZED.on(property))
}
@@ -681,11 +682,9 @@ class DeclarationsChecker(
else if (noExplicitTypeOrGetterType(property)) {
trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property))
}
if (backingFieldRequired && !inTrait && propertyDescriptor.isLateInit && !isUninitialized) {
if (trace[MUST_BE_LATEINIT, propertyDescriptor] ?: false) {}
else {
trace.report(UNNECESSARY_LATEINIT.on(property))
}
if (backingFieldRequired && !inTrait && propertyDescriptor.isLateInit && !isUninitialized &&
trace[MUST_BE_LATEINIT, propertyDescriptor] != true) {
trace.report(UNNECESSARY_LATEINIT.on(property))
}
}
}
@@ -800,11 +799,18 @@ class DeclarationsChecker(
private fun checkAccessor(
propertyDescriptor: PropertyDescriptor,
accessor: KtPropertyAccessor?,
accessorDescriptor: PropertyAccessorDescriptor?) {
accessorDescriptor: PropertyAccessorDescriptor?
) {
if (accessor == null || accessorDescriptor == null) return
if (propertyDescriptor.isPlatform && accessor.hasBody()) {
trace.report(PLATFORM_DECLARATION_WITH_BODY.on(accessor))
}
val accessorModifierList = accessor.modifierList ?: return
val tokens = modifiersChecker.getTokensCorrespondingToModifiers(accessorModifierList,
Sets.newHashSet(KtTokens.PUBLIC_KEYWORD, KtTokens.PROTECTED_KEYWORD, KtTokens.PRIVATE_KEYWORD, KtTokens.INTERNAL_KEYWORD))
val tokens = modifiersChecker.getTokensCorrespondingToModifiers(
accessorModifierList,
setOf(KtTokens.PUBLIC_KEYWORD, KtTokens.PROTECTED_KEYWORD, KtTokens.PRIVATE_KEYWORD, KtTokens.INTERNAL_KEYWORD)
)
if (accessor.isGetter) {
if (accessorDescriptor.visibility != propertyDescriptor.visibility) {
reportVisibilityModifierDiagnostics(tokens.values, Errors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY)
@@ -808,7 +808,10 @@ public class DescriptorResolver {
CallableMemberDescriptor.Kind.DECLARATION,
KotlinSourceElementKt.toSourceElement(property),
modifierList != null && modifierList.hasModifier(KtTokens.LATEINIT_KEYWORD),
modifierList != null && modifierList.hasModifier(KtTokens.CONST_KEYWORD)
modifierList != null && modifierList.hasModifier(KtTokens.CONST_KEYWORD),
modifierList != null && modifierList.hasModifier(KtTokens.PLATFORM_KEYWORD) ||
containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor) containingDeclaration).isPlatform(),
modifierList != null && modifierList.hasModifier(KtTokens.IMPL_KEYWORD)
);
wrapper.setDescriptor(propertyDescriptor);
@@ -1123,7 +1126,9 @@ public class DescriptorResolver {
CallableMemberDescriptor.Kind.DECLARATION,
KotlinSourceElementKt.toSourceElement(parameter),
/* lateInit = */ false,
/* isConst = */ false
/* isConst = */ false,
/* isPlatform = */ false,
/* isImpl = */ false
);
propertyWrapper.setDescriptor(propertyDescriptor);
propertyDescriptor.setType(type, Collections.<TypeParameterDescriptor>emptyList(),
@@ -85,14 +85,14 @@ class LocalVariableResolver(
propertyDescriptor,
delegateExpression,
typingContext.scope,
typingContext.trace);
typingContext.trace)
}
}
val initializer = property.initializer
var typeInfo: KotlinTypeInfo
if (initializer != null) {
val outType = propertyDescriptor.getType()
val outType = propertyDescriptor.type
typeInfo = facade.getTypeInfo(initializer, context.replaceExpectedType(outType))
val dataFlowInfo = typeInfo.dataFlowInfo
val type = typeInfo.type
@@ -146,7 +146,9 @@ class LocalVariableResolver(
CallableMemberDescriptor.Kind.DECLARATION,
variable.toSourceElement(),
/* lateInit = */ false,
/* isConst = */ false
/* isConst = */ false,
/* isPlatform = */ false,
/* isImpl = */ false
)
// For a local variable the type must not be deferred
type = variableTypeAndInitializerResolver.resolveType(propertyDescriptor, scope, variable, dataFlowInfo, trace, local = true)
@@ -90,8 +90,8 @@ object ModifierCheckerCore {
CONST_KEYWORD to EnumSet.of(MEMBER_PROPERTY, TOP_LEVEL_PROPERTY),
OPERATOR_KEYWORD to EnumSet.of(FUNCTION),
INFIX_KEYWORD to EnumSet.of(FUNCTION),
PLATFORM_KEYWORD to EnumSet.of(FUNCTION, CLASS_ONLY, OBJECT, INTERFACE, INNER_CLASS, ENUM_CLASS, ANNOTATION_CLASS), // TODO
IMPL_KEYWORD to EnumSet.of(FUNCTION, CLASS_ONLY, OBJECT, INTERFACE, INNER_CLASS, ENUM_CLASS, ANNOTATION_CLASS) // TODO
PLATFORM_KEYWORD to EnumSet.of(FUNCTION, TOP_LEVEL_PROPERTY_WITHOUT_FIELD_OR_DELEGATE, CLASS_ONLY, OBJECT, INTERFACE, INNER_CLASS, ENUM_CLASS, ANNOTATION_CLASS), // TODO
IMPL_KEYWORD to EnumSet.of(FUNCTION, TOP_LEVEL_PROPERTY_WITHOUT_FIELD_OR_DELEGATE, CLASS_ONLY, OBJECT, INTERFACE, INNER_CLASS, ENUM_CLASS, ANNOTATION_CLASS) // TODO
)
val featureDependencies = mapOf(
@@ -97,7 +97,9 @@ class DynamicCallableDescriptors(storageManager: StorageManager, builtIns: Kotli
CallableMemberDescriptor.Kind.DECLARATION,
SourceElement.NO_SOURCE,
/* lateInit = */ false,
/* isConst = */ false
/* isConst = */ false,
/* isPlatform = */ false,
/* isImpl = */ false
)
propertyDescriptor.setType(
dynamicType,