Changed name resolution for dynamic extension. Added annotation DynamicExtension.

This commit is contained in:
Stanislav Erokhin
2016-12-14 00:50:16 +03:00
parent 91fcb15f3e
commit 457918a6dd
34 changed files with 319 additions and 61 deletions
@@ -828,6 +828,8 @@ public interface Errors {
DiagnosticFactory0<PsiElement> ABBREVIATED_NOTHING_PROPERTY_TYPE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<PsiElement, KotlinType> IMPLICIT_INTERSECTION_TYPE = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<KtCallableDeclaration> DYNAMIC_RECEIVER_NOT_ALLOWED = DiagnosticFactory0.create(ERROR, PositioningStrategies.RECEIVER);
// Context tracking
DiagnosticFactory1<KtExpression, KtExpression> EXPRESSION_EXPECTED = DiagnosticFactory1.create(ERROR);
@@ -492,4 +492,11 @@ object PositioningStrategies {
return markElement(element.returnKeyword)
}
}
@JvmField val RECEIVER: PositioningStrategy<KtCallableDeclaration> = object : DeclarationHeader<KtCallableDeclaration>() {
override fun mark(element: KtCallableDeclaration): List<TextRange> {
element.receiverTypeReference?.let { return markElement(it) }
return DEFAULT.mark(element)
}
}
}
@@ -635,6 +635,8 @@ public class DefaultErrorMessages {
MAP.put(IMPLICIT_INTERSECTION_TYPE, "Inferred type {0} is an intersection, please specify the required type explicitly", RENDER_TYPE);
MAP.put(EXPECTED_CONDITION, "Expected condition of type Boolean");
MAP.put(DYNAMIC_RECEIVER_NOT_ALLOWED, "Dynamic receiver is prohibited");
MAP.put(CANNOT_CHECK_FOR_ERASED, "Cannot check for instance of erased type: {0}", RENDER_TYPE);
MAP.put(UNCHECKED_CAST, "Unchecked cast: {0} to {1}", RENDER_TYPE, RENDER_TYPE);
@@ -75,7 +75,8 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf(
InfixModifierChecker(),
CoroutineModifierChecker,
SinceKotlinAnnotationValueChecker,
ReifiedTypeParameterAnnotationChecker()
ReifiedTypeParameterAnnotationChecker(),
DynamicReceiverChecker
)
private val DEFAULT_CALL_CHECKERS = listOf(
@@ -43,6 +43,7 @@ import org.jetbrains.kotlin.resolve.calls.results.ResolutionResultsHandler
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.tasks.*
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDynamicExtensionAnnotation
import org.jetbrains.kotlin.resolve.isHiddenInResolution
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.MemberScope
@@ -347,10 +348,21 @@ class NewResolutionOldInference(
basicCallContext.dataFlowInfoForArguments // todo may be we should create new mutable info for arguments
)
// see spec-docs/dynamic-types.md
if (extensionReceiver != null && extensionReceiver.receiverValue.type.isDynamic()
&& !towerCandidate.descriptor.extensionReceiverParameter!!.value.type.isDynamic()) {
return MyCandidate(ResolutionCandidateStatus(listOf(ExtensionWithStaticTypeWithDynamicReceiver)), candidateCall)
/**
* See https://jetbrains.quip.com/qcTDAFcgFLEM
*
* For now we have only 2 functions with dynamic receivers: iterator() and unsafeCast()
* Both this function are marked via @kotlin.internal.DynamicExtension.
*/
if (extensionReceiver != null) {
val parameterIsDynamic = towerCandidate.descriptor.extensionReceiverParameter!!.value.type.isDynamic()
val argumentIsDynamic = extensionReceiver.receiverValue.type.isDynamic()
if (parameterIsDynamic != argumentIsDynamic ||
(parameterIsDynamic && !towerCandidate.descriptor.hasDynamicExtensionAnnotation())
) {
return MyCandidate(ResolutionCandidateStatus(listOf(HiddenExtensionRelatedToDynamicTypes)), candidateCall)
}
}
if (towerCandidate.descriptor.isHiddenInResolution(languageVersionSettings, basicCallContext.isSuperCall)) {
@@ -0,0 +1,46 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.resolve.checkers
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.KtCallableDeclaration
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDynamicExtensionAnnotation
import org.jetbrains.kotlin.types.isDynamic
object DynamicReceiverChecker : SimpleDeclarationChecker {
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
if (descriptor !is CallableDescriptor || declaration !is KtCallableDeclaration || descriptor.hasDynamicExtensionAnnotation()) return
// function expression
if (declaration is KtNamedFunction && declaration.name == null) return
if (descriptor.extensionReceiverParameter?.value?.type?.isDynamic() == true) {
diagnosticHolder.report(Errors.DYNAMIC_RECEIVER_NOT_ALLOWED.on(declaration))
}
}
}