diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDelegateUsesExtensionPropertyTypeParameterChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDelegateUsesExtensionPropertyTypeParameterChecker.kt index fb4a6defb77..db11acfe93d 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDelegateUsesExtensionPropertyTypeParameterChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDelegateUsesExtensionPropertyTypeParameterChecker.kt @@ -8,14 +8,16 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.declarations.FirProperty import org.jetbrains.kotlin.fir.expressions.FirFunctionCall +import org.jetbrains.kotlin.fir.resolve.fullyExpandedType +import org.jetbrains.kotlin.fir.resolve.toSymbol +import org.jetbrains.kotlin.fir.scopes.processAllProperties +import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol -import org.jetbrains.kotlin.fir.types.ConeKotlinType -import org.jetbrains.kotlin.fir.types.coneType -import org.jetbrains.kotlin.fir.types.toSymbol -import org.jetbrains.kotlin.fir.types.type +import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.utils.addToStdlib.safeAs object FirDelegateUsesExtensionPropertyTypeParameterChecker : FirPropertyChecker() { @@ -30,17 +32,32 @@ object FirDelegateUsesExtensionPropertyTypeParameterChecker : FirPropertyChecker } private fun ConeKotlinType.findUsedTypeParameterSymbol( - parameters: HashSet, + typeParameterSymbols: HashSet, delegate: FirFunctionCall, context: CheckerContext, reporter: DiagnosticReporter, ): FirTypeParameterSymbol? { + val expandedDelegateClassLikeType = + delegate.typeRef.coneType.lowerBoundIfFlexible().fullyExpandedType(context.session) + .unwrapDefinitelyNotNull() as? ConeClassLikeType ?: return null + val delegateClassSymbol = expandedDelegateClassLikeType.lookupTag.toSymbol(context.session) as? FirRegularClassSymbol ?: return null + val delegateClassScope by lazy { delegateClassSymbol.unsubstitutedScope(context) } for (it in typeArguments) { val theType = it.type ?: continue - val symbol = theType.toSymbol(context.session) as? FirTypeParameterSymbol + val argumentAsTypeParameterSymbol = theType.toSymbol(context.session) as? FirTypeParameterSymbol - if (symbol in parameters) return symbol - val usedTypeParameterSymbol = theType.findUsedTypeParameterSymbol(parameters, delegate, context, reporter) + if (argumentAsTypeParameterSymbol in typeParameterSymbols) { + var propertyWithTypeParameterTypeFound = false + delegateClassScope.processAllProperties { symbol -> + if (symbol.resolvedReturnType.contains { it is ConeTypeParameterType }) { + propertyWithTypeParameterTypeFound = true + } + } + if (propertyWithTypeParameterTypeFound) { + return argumentAsTypeParameterSymbol + } + } + val usedTypeParameterSymbol = theType.findUsedTypeParameterSymbol(typeParameterSymbols, delegate, context, reporter) if (usedTypeParameterSymbol != null) { return usedTypeParameterSymbol } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt index b1565773681..adc1b304982 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt @@ -26,8 +26,8 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0 -import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors.* +import org.jetbrains.kotlin.incremental.KotlinLookupLocation import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier @@ -494,7 +494,7 @@ class DeclarationsChecker( val declaration = classOrObject.primaryConstructor ?: return for (parameter in declaration.valueParameters) { - trace.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter)?.let { + trace.get(PRIMARY_CONSTRUCTOR_PARAMETER, parameter)?.let { modifiersChecker.checkModifiersForDeclaration(parameter, it) LateinitModifierApplicabilityChecker.checkLateinitModifierApplicability(trace, parameter, it) } @@ -703,7 +703,7 @@ class DeclarationsChecker( return } - val backingFieldRequired = trace.bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor) ?: false + val backingFieldRequired = trace.bindingContext.get(BACKING_FIELD_REQUIRED, propertyDescriptor) ?: false if (inInterface && backingFieldRequired && hasAccessorImplementation) { trace.report(BACKING_FIELD_IN_INTERFACE.on(property)) } @@ -726,6 +726,15 @@ class DeclarationsChecker( trace.report(EXPECTED_DELEGATED_PROPERTY.on(delegate)) } else if (property.receiverTypeReference != null) { val delegatedPropertyResolvedCall = trace.get(DELEGATED_PROPERTY_RESOLVED_CALL, propertyDescriptor.getter) + val provideDelegateResolvedCall = trace.get(PROVIDE_DELEGATE_RESOLVED_CALL, propertyDescriptor) + val delegateType = provideDelegateResolvedCall?.resultingDescriptor?.returnType + ?: delegate.expression?.let { trace.getType(it) } ?: return + + val delegateClassDescriptor = + delegateType.lowerIfFlexible().unwrap().constructor.declarationDescriptor.let { + it as? ClassDescriptor ?: (it as? TypeAliasDescriptor)?.expandedType?.constructor?.declarationDescriptor + } as? ClassDescriptor ?: return + val delegateClassScope by lazy { delegateClassDescriptor.unsubstitutedMemberScope } val dispatchReceiverType = delegatedPropertyResolvedCall?.dispatchReceiver?.type val extensionReceiverType = delegatedPropertyResolvedCall?.extensionReceiver?.type val usedParameter = propertyDescriptor.typeParameters.find { typeParameter -> @@ -733,6 +742,18 @@ class DeclarationsChecker( extensionReceiverType?.contains { it.constructor == typeParameter.typeConstructor } == true } if (usedParameter != null) { + var propertyWithTypeParameterTypeFound = false + val names = delegateClassScope.getVariableNames() + for (name in names) { + delegateClassScope.getContributedVariables(name, KotlinLookupLocation(delegate)) + .forEach { propertyInDelegateClass -> + if (propertyInDelegateClass.type.contains { it.constructor.declarationDescriptor is TypeParameterDescriptor }) { + propertyWithTypeParameterTypeFound = true + return@forEach + } + } + } + if (!propertyWithTypeParameterTypeFound) return trace.report( DELEGATE_USES_EXTENSION_PROPERTY_TYPE_PARAMETER.on( languageVersionSettings, @@ -743,7 +764,7 @@ class DeclarationsChecker( } } } else { - val isUninitialized = trace.bindingContext.get(BindingContext.IS_UNINITIALIZED, propertyDescriptor) ?: false + val isUninitialized = trace.bindingContext.get(IS_UNINITIALIZED, propertyDescriptor) ?: false val isExternal = propertyDescriptor.isEffectivelyExternal() if (backingFieldRequired && !inInterface && !propertyDescriptor.isLateInit && !isExpect && isUninitialized && !isExternal) { if (propertyDescriptor.extensionReceiverParameter != null && !hasAccessorImplementation) { @@ -757,7 +778,7 @@ class DeclarationsChecker( } } else if (property.typeReference == null && !languageVersionSettings.supportsFeature(LanguageFeature.ShortSyntaxForPropertyGetters)) { trace.report( - Errors.UNSUPPORTED_FEATURE.on( + UNSUPPORTED_FEATURE.on( property, LanguageFeature.ShortSyntaxForPropertyGetters to languageVersionSettings ) @@ -920,9 +941,9 @@ class DeclarationsChecker( ) if (accessor.isGetter) { if (accessorDescriptor.visibility != propertyDescriptor.visibility) { - reportVisibilityModifierDiagnostics(tokens.values, Errors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY) + reportVisibilityModifierDiagnostics(tokens.values, GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY) } else { - reportVisibilityModifierDiagnostics(tokens.values, Errors.REDUNDANT_MODIFIER_IN_GETTER) + reportVisibilityModifierDiagnostics(tokens.values, REDUNDANT_MODIFIER_IN_GETTER) } } else { if (propertyDescriptor.isOverridable @@ -930,14 +951,14 @@ class DeclarationsChecker( && propertyDescriptor.visibility != DescriptorVisibilities.PRIVATE ) { if (propertyDescriptor.modality == Modality.ABSTRACT) { - reportVisibilityModifierDiagnostics(tokens.values, Errors.PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY) + reportVisibilityModifierDiagnostics(tokens.values, PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY) } else { - reportVisibilityModifierDiagnostics(tokens.values, Errors.PRIVATE_SETTER_FOR_OPEN_PROPERTY) + reportVisibilityModifierDiagnostics(tokens.values, PRIVATE_SETTER_FOR_OPEN_PROPERTY) } } else { val compare = DescriptorVisibilities.compare(accessorDescriptor.visibility, propertyDescriptor.visibility) if (compare == null || compare > 0) { - reportVisibilityModifierDiagnostics(tokens.values, Errors.SETTER_VISIBILITY_INCONSISTENT_WITH_PROPERTY_VISIBILITY) + reportVisibilityModifierDiagnostics(tokens.values, SETTER_VISIBILITY_INCONSISTENT_WITH_PROPERTY_VISIBILITY) } } } diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/useTypeParameterOfExtensionProperty2.kt b/compiler/testData/diagnostics/tests/delegatedProperty/useTypeParameterOfExtensionProperty2.kt index c10c93be560..46dbe6fdd28 100644 --- a/compiler/testData/diagnostics/tests/delegatedProperty/useTypeParameterOfExtensionProperty2.kt +++ b/compiler/testData/diagnostics/tests/delegatedProperty/useTypeParameterOfExtensionProperty2.kt @@ -11,7 +11,7 @@ fun logged(getter: (T) -> V) = getter(thisRef) } -val List.second: T by logged { it[1] } +val List.second: T by logged { it[1] } class Delegate(private val fn: (List) -> T) { private var cache: T? = null