KT-15844
Property with type inferred from getter could access primary constructor parameters inside the getter (which is incorrect, and caused problems in compilation). Fix scopes for property descriptor resolution. 'getScopeForMemberDeclarationResolution' in AbstractLazyMemberScope should always return member declaration resolution scope. Two scopes are required, because both property initializer and property accessors should see property type parameters.
This commit is contained in:
@@ -402,6 +402,20 @@ public class DescriptorResolver {
|
||||
LexicalScope scopeForAnnotationsResolve,
|
||||
List<KtTypeParameter> typeParameters,
|
||||
BindingTrace trace
|
||||
) {
|
||||
List<TypeParameterDescriptorImpl> descriptors =
|
||||
resolveTypeParametersForDescriptor(containingDescriptor, scopeForAnnotationsResolve, typeParameters, trace);
|
||||
for (TypeParameterDescriptorImpl descriptor : descriptors) {
|
||||
extensibleScope.addClassifierDescriptor(descriptor);
|
||||
}
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
private List<TypeParameterDescriptorImpl> resolveTypeParametersForDescriptor(
|
||||
DeclarationDescriptor containingDescriptor,
|
||||
LexicalScope scopeForAnnotationsResolve,
|
||||
List<KtTypeParameter> typeParameters,
|
||||
BindingTrace trace
|
||||
) {
|
||||
assert containingDescriptor instanceof FunctionDescriptor ||
|
||||
containingDescriptor instanceof PropertyDescriptor ||
|
||||
@@ -411,15 +425,13 @@ public class DescriptorResolver {
|
||||
List<TypeParameterDescriptorImpl> result = new ArrayList<TypeParameterDescriptorImpl>();
|
||||
for (int i = 0, typeParametersSize = typeParameters.size(); i < typeParametersSize; i++) {
|
||||
KtTypeParameter typeParameter = typeParameters.get(i);
|
||||
result.add(resolveTypeParameterForDescriptor(
|
||||
containingDescriptor, extensibleScope, scopeForAnnotationsResolve, typeParameter, i, trace));
|
||||
result.add(resolveTypeParameterForDescriptor(containingDescriptor, scopeForAnnotationsResolve, typeParameter, i, trace));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private TypeParameterDescriptorImpl resolveTypeParameterForDescriptor(
|
||||
final DeclarationDescriptor containingDescriptor,
|
||||
LexicalWritableScope extensibleScope,
|
||||
LexicalScope scopeForAnnotationsResolve,
|
||||
final KtTypeParameter typeParameter,
|
||||
int index,
|
||||
@@ -452,7 +464,6 @@ public class DescriptorResolver {
|
||||
supertypeLoopsResolver
|
||||
);
|
||||
trace.record(BindingContext.TYPE_PARAMETER, typeParameter, typeParameterDescriptor);
|
||||
extensibleScope.addClassifierDescriptor(typeParameterDescriptor);
|
||||
return typeParameterDescriptor;
|
||||
}
|
||||
|
||||
@@ -777,7 +788,8 @@ public class DescriptorResolver {
|
||||
@NotNull
|
||||
public PropertyDescriptor resolvePropertyDescriptor(
|
||||
@NotNull DeclarationDescriptor containingDeclaration,
|
||||
@NotNull LexicalScope scope,
|
||||
@NotNull LexicalScope scopeForDeclarationResolution,
|
||||
@NotNull LexicalScope scopeForInitializerResolution,
|
||||
@NotNull KtProperty property,
|
||||
@NotNull final BindingTrace trace,
|
||||
@NotNull DataFlowInfo dataFlowInfo
|
||||
@@ -794,7 +806,7 @@ public class DescriptorResolver {
|
||||
|
||||
final AnnotationSplitter.PropertyWrapper wrapper = new AnnotationSplitter.PropertyWrapper(property);
|
||||
|
||||
Annotations allAnnotations = annotationResolver.resolveAnnotationsWithoutArguments(scope, modifierList, trace);
|
||||
Annotations allAnnotations = annotationResolver.resolveAnnotationsWithoutArguments(scopeForDeclarationResolution, modifierList, trace);
|
||||
AnnotationSplitter annotationSplitter =
|
||||
new AnnotationSplitter(storageManager, allAnnotations, new Function0<Set<AnnotationUseSiteTarget>>() {
|
||||
@Override
|
||||
@@ -826,43 +838,55 @@ public class DescriptorResolver {
|
||||
wrapper.setDescriptor(propertyDescriptor);
|
||||
|
||||
List<TypeParameterDescriptorImpl> typeParameterDescriptors;
|
||||
LexicalScope scopeWithTypeParameters;
|
||||
LexicalScope scopeForDeclarationResolutionWithTypeParameters;
|
||||
LexicalScope scopeForInitializerResolutionWithTypeParameters;
|
||||
KotlinType receiverType = null;
|
||||
|
||||
{
|
||||
List<KtTypeParameter> typeParameters = property.getTypeParameters();
|
||||
if (typeParameters.isEmpty()) {
|
||||
scopeWithTypeParameters = scope;
|
||||
scopeForDeclarationResolutionWithTypeParameters = scopeForDeclarationResolution;
|
||||
scopeForInitializerResolutionWithTypeParameters = scopeForInitializerResolution;
|
||||
typeParameterDescriptors = Collections.emptyList();
|
||||
}
|
||||
else {
|
||||
LexicalWritableScope writableScope = new LexicalWritableScope(
|
||||
scope, containingDeclaration, false, new TraceBasedLocalRedeclarationChecker(trace, overloadChecker),
|
||||
LexicalWritableScope writableScopeForDeclarationResolution = new LexicalWritableScope(
|
||||
scopeForDeclarationResolution, containingDeclaration, false, new TraceBasedLocalRedeclarationChecker(trace, overloadChecker),
|
||||
LexicalScopeKind.PROPERTY_HEADER);
|
||||
LexicalWritableScope writableScopeForInitializerResolution = new LexicalWritableScope(
|
||||
scopeForInitializerResolution, containingDeclaration, false, LocalRedeclarationChecker.DO_NOTHING.INSTANCE,
|
||||
LexicalScopeKind.PROPERTY_HEADER);
|
||||
typeParameterDescriptors = resolveTypeParametersForDescriptor(
|
||||
propertyDescriptor, writableScope, scope, typeParameters, trace);
|
||||
writableScope.freeze();
|
||||
resolveGenericBounds(property, propertyDescriptor, writableScope, typeParameterDescriptors, trace);
|
||||
scopeWithTypeParameters = writableScope;
|
||||
propertyDescriptor,
|
||||
scopeForDeclarationResolution, typeParameters, trace);
|
||||
for (TypeParameterDescriptor descriptor : typeParameterDescriptors) {
|
||||
writableScopeForDeclarationResolution.addClassifierDescriptor(descriptor);
|
||||
writableScopeForInitializerResolution.addClassifierDescriptor(descriptor);
|
||||
}
|
||||
writableScopeForDeclarationResolution.freeze();
|
||||
writableScopeForInitializerResolution.freeze();
|
||||
resolveGenericBounds(property, propertyDescriptor, writableScopeForDeclarationResolution, typeParameterDescriptors, trace);
|
||||
scopeForDeclarationResolutionWithTypeParameters = writableScopeForDeclarationResolution;
|
||||
scopeForInitializerResolutionWithTypeParameters = writableScopeForInitializerResolution;
|
||||
}
|
||||
|
||||
KtTypeReference receiverTypeRef = property.getReceiverTypeReference();
|
||||
if (receiverTypeRef != null) {
|
||||
receiverType = typeResolver.resolveType(scopeWithTypeParameters, receiverTypeRef, trace, true);
|
||||
receiverType = typeResolver.resolveType(scopeForDeclarationResolutionWithTypeParameters, receiverTypeRef, trace, true);
|
||||
}
|
||||
}
|
||||
|
||||
ReceiverParameterDescriptor receiverDescriptor =
|
||||
DescriptorFactory.createExtensionReceiverParameterForCallable(propertyDescriptor, receiverType);
|
||||
|
||||
LexicalScope scopeForInitializer = ScopeUtils.makeScopeForPropertyInitializer(scopeWithTypeParameters, propertyDescriptor);
|
||||
LexicalScope scopeForInitializer = ScopeUtils.makeScopeForPropertyInitializer(scopeForInitializerResolutionWithTypeParameters, propertyDescriptor);
|
||||
KotlinType typeIfKnown = variableTypeAndInitializerResolver.resolveTypeNullable(
|
||||
propertyDescriptor, scopeForInitializer,
|
||||
property, dataFlowInfo, /* local = */ trace, false
|
||||
);
|
||||
|
||||
PropertyGetterDescriptorImpl getter = resolvePropertyGetterDescriptor(
|
||||
scopeWithTypeParameters, property, propertyDescriptor, annotationSplitter, trace, typeIfKnown);
|
||||
scopeForDeclarationResolutionWithTypeParameters, property, propertyDescriptor, annotationSplitter, trace, typeIfKnown);
|
||||
|
||||
KotlinType type = typeIfKnown != null ? typeIfKnown : getter.getReturnType();
|
||||
|
||||
@@ -876,7 +900,7 @@ public class DescriptorResolver {
|
||||
receiverDescriptor);
|
||||
|
||||
PropertySetterDescriptor setter = resolvePropertySetterDescriptor(
|
||||
scopeWithTypeParameters, property, propertyDescriptor, annotationSplitter, trace);
|
||||
scopeForDeclarationResolutionWithTypeParameters, property, propertyDescriptor, annotationSplitter, trace);
|
||||
|
||||
propertyDescriptor.initialize(getter, setter);
|
||||
|
||||
@@ -1007,7 +1031,7 @@ public class DescriptorResolver {
|
||||
|
||||
@NotNull
|
||||
private PropertyGetterDescriptorImpl resolvePropertyGetterDescriptor(
|
||||
@NotNull LexicalScope scopeWithTypeParameters,
|
||||
@NotNull LexicalScope scopeForDeclarationResolution,
|
||||
@NotNull KtProperty property,
|
||||
@NotNull PropertyDescriptor propertyDescriptor,
|
||||
@NotNull AnnotationSplitter annotationSplitter,
|
||||
@@ -1020,7 +1044,7 @@ public class DescriptorResolver {
|
||||
if (getter != null) {
|
||||
Annotations getterAnnotations = new CompositeAnnotations(CollectionsKt.listOf(
|
||||
annotationSplitter.getAnnotationsForTarget(PROPERTY_GETTER),
|
||||
annotationResolver.resolveAnnotationsWithoutArguments(scopeWithTypeParameters, getter.getModifierList(), trace)));
|
||||
annotationResolver.resolveAnnotationsWithoutArguments(scopeForDeclarationResolution, getter.getModifierList(), trace)));
|
||||
|
||||
getterDescriptor = new PropertyGetterDescriptorImpl(
|
||||
propertyDescriptor, getterAnnotations,
|
||||
@@ -1031,7 +1055,7 @@ public class DescriptorResolver {
|
||||
property.hasModifier(KtTokens.INLINE_KEYWORD) || getter.hasModifier(KtTokens.INLINE_KEYWORD),
|
||||
CallableMemberDescriptor.Kind.DECLARATION, null, KotlinSourceElementKt.toSourceElement(getter)
|
||||
);
|
||||
getterType = determineGetterReturnType(scopeWithTypeParameters, trace, getterDescriptor, getter, propertyTypeIfKnown);
|
||||
getterType = determineGetterReturnType(scopeForDeclarationResolution, trace, getterDescriptor, getter, propertyTypeIfKnown);
|
||||
trace.record(BindingContext.PROPERTY_ACCESSOR, getter, getterDescriptor);
|
||||
}
|
||||
else {
|
||||
|
||||
+5
-4
@@ -82,10 +82,9 @@ protected constructor(
|
||||
|
||||
val declarations = declarationProvider.getFunctionDeclarations(name)
|
||||
for (functionDeclaration in declarations) {
|
||||
val resolutionScope = getScopeForMemberDeclarationResolution(functionDeclaration)
|
||||
result.add(c.functionDescriptorResolver.resolveFunctionDescriptor(
|
||||
thisDescriptor,
|
||||
resolutionScope,
|
||||
getScopeForMemberDeclarationResolution(functionDeclaration),
|
||||
functionDeclaration,
|
||||
trace,
|
||||
c.declarationScopeProvider.getOuterDataFlowInfoForDeclaration(functionDeclaration)))
|
||||
@@ -98,6 +97,8 @@ protected constructor(
|
||||
|
||||
protected abstract fun getScopeForMemberDeclarationResolution(declaration: KtDeclaration): LexicalScope
|
||||
|
||||
protected abstract fun getScopeForInitializerResolution(declaration: KtDeclaration): LexicalScope
|
||||
|
||||
protected abstract fun getNonDeclaredClasses(name: Name, result: MutableSet<ClassDescriptor>)
|
||||
|
||||
protected abstract fun getNonDeclaredFunctions(name: Name, result: MutableSet<SimpleFunctionDescriptor>)
|
||||
@@ -112,10 +113,10 @@ protected constructor(
|
||||
|
||||
val declarations = declarationProvider.getPropertyDeclarations(name)
|
||||
for (propertyDeclaration in declarations) {
|
||||
val resolutionScope = getScopeForMemberDeclarationResolution(propertyDeclaration)
|
||||
val propertyDescriptor = c.descriptorResolver.resolvePropertyDescriptor(
|
||||
thisDescriptor,
|
||||
resolutionScope,
|
||||
getScopeForMemberDeclarationResolution(propertyDeclaration),
|
||||
getScopeForInitializerResolution(propertyDeclaration),
|
||||
propertyDeclaration,
|
||||
trace,
|
||||
c.declarationScopeProvider.getOuterDataFlowInfoForDeclaration(propertyDeclaration))
|
||||
|
||||
+5
-6
@@ -95,12 +95,11 @@ open class LazyClassMemberScope(
|
||||
private val primaryConstructor: NullableLazyValue<ClassConstructorDescriptor>
|
||||
= c.storageManager.createNullableLazyValue { resolvePrimaryConstructor() }
|
||||
|
||||
override fun getScopeForMemberDeclarationResolution(declaration: KtDeclaration): LexicalScope {
|
||||
if (declaration is KtProperty) {
|
||||
return thisDescriptor.scopeForInitializerResolution
|
||||
}
|
||||
return thisDescriptor.scopeForMemberDeclarationResolution
|
||||
}
|
||||
override fun getScopeForMemberDeclarationResolution(declaration: KtDeclaration): LexicalScope =
|
||||
thisDescriptor.scopeForMemberDeclarationResolution
|
||||
|
||||
override fun getScopeForInitializerResolution(declaration: KtDeclaration): LexicalScope =
|
||||
thisDescriptor.scopeForInitializerResolution
|
||||
|
||||
private fun <D : CallableMemberDescriptor> generateFakeOverrides(name: Name, fromSupertypes: Collection<D>, result: MutableCollection<D>, exactDescriptorClass: Class<out D>) {
|
||||
OverridingUtil.generateOverridesInFunctionGroup(name, fromSupertypes, ArrayList(result), thisDescriptor, object : OverridingStrategy() {
|
||||
|
||||
+5
-2
@@ -36,8 +36,11 @@ class LazyPackageMemberScope(
|
||||
return computeDescriptorsFromDeclaredElements(kindFilter, nameFilter, NoLookupLocation.WHEN_GET_ALL_DESCRIPTORS)
|
||||
}
|
||||
|
||||
override fun getScopeForMemberDeclarationResolution(declaration: KtDeclaration)
|
||||
= resolveSession.fileScopeProvider.getFileResolutionScope(declaration.getContainingKtFile())
|
||||
override fun getScopeForMemberDeclarationResolution(declaration: KtDeclaration) =
|
||||
resolveSession.fileScopeProvider.getFileResolutionScope(declaration.containingKtFile)
|
||||
|
||||
override fun getScopeForInitializerResolution(declaration: KtDeclaration) =
|
||||
getScopeForMemberDeclarationResolution(declaration)
|
||||
|
||||
override fun getNonDeclaredClasses(name: Name, result: MutableSet<ClassDescriptor>) {
|
||||
// No extra classes
|
||||
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
object Delegate {
|
||||
operator fun getValue(x: Any?, y: Any?): String = ""
|
||||
}
|
||||
|
||||
fun <T> delegateFactory(p: Any) = Delegate
|
||||
|
||||
class C(p: Any, val v: Any) {
|
||||
|
||||
val test1 get() = <!UNRESOLVED_REFERENCE!>p<!>
|
||||
|
||||
val test2 get() = v
|
||||
|
||||
// NB here we can use both 'T' (property type parameter) and 'p' (primary constructor parameter)
|
||||
val <T> List<T>.test3 by delegateFactory<T>(p)
|
||||
|
||||
<!PROPERTY_WITH_NO_TYPE_NO_INITIALIZER!>val test4<!> get() { return <!UNRESOLVED_REFERENCE!>p<!> }
|
||||
|
||||
<!PROPERTY_WITH_NO_TYPE_NO_INITIALIZER!>var test5<!>
|
||||
get() { return <!UNRESOLVED_REFERENCE!>p<!> }
|
||||
set(nv) { <!UNRESOLVED_REFERENCE!>p<!>.<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>let<!> {} }
|
||||
}
|
||||
Vendored
+24
@@ -0,0 +1,24 @@
|
||||
package
|
||||
|
||||
public fun </*0*/ T> delegateFactory(/*0*/ p: kotlin.Any): Delegate
|
||||
|
||||
public final class C {
|
||||
public constructor C(/*0*/ p: kotlin.Any, /*1*/ v: kotlin.Any)
|
||||
public final val test1: [ERROR : Error function type]
|
||||
public final val test2: kotlin.Any
|
||||
public final val test4: [ERROR : No type, no body]
|
||||
public final var test5: [ERROR : No type, no body]
|
||||
public final val v: kotlin.Any
|
||||
public final val </*0*/ T> kotlin.collections.List<T>.test3: kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public object Delegate {
|
||||
private constructor Delegate()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public final operator fun getValue(/*0*/ x: kotlin.Any?, /*1*/ y: kotlin.Any?): kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -15612,6 +15612,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("primaryConstructorParameter.kt")
|
||||
public void testPrimaryConstructorParameter() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/properties/inferenceFromGetters/primaryConstructorParameter.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("recursiveGetter.kt")
|
||||
public void testRecursiveGetter() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/properties/inferenceFromGetters/recursiveGetter.kt");
|
||||
|
||||
@@ -145,7 +145,7 @@ public class DefaultModalityModifiersTest extends KotlinTestWithEnvironment {
|
||||
List<KtDeclaration> declarations = aClass.getDeclarations();
|
||||
KtProperty property = (KtProperty) declarations.get(0);
|
||||
PropertyDescriptor propertyDescriptor = descriptorResolver.resolvePropertyDescriptor(
|
||||
classDescriptor, scope, property, KotlinTestUtils.DUMMY_TRACE, DataFlowInfoFactory.EMPTY);
|
||||
classDescriptor, scope, scope, property, KotlinTestUtils.DUMMY_TRACE, DataFlowInfoFactory.EMPTY);
|
||||
|
||||
assertEquals(expectedPropertyModality, propertyDescriptor.getModality());
|
||||
}
|
||||
@@ -158,7 +158,7 @@ public class DefaultModalityModifiersTest extends KotlinTestWithEnvironment {
|
||||
List<KtDeclaration> declarations = aClass.getDeclarations();
|
||||
KtProperty property = (KtProperty) declarations.get(0);
|
||||
PropertyDescriptor propertyDescriptor = descriptorResolver.resolvePropertyDescriptor(
|
||||
classDescriptor, scope, property, KotlinTestUtils.DUMMY_TRACE, DataFlowInfoFactory.EMPTY);
|
||||
classDescriptor, scope, scope, property, KotlinTestUtils.DUMMY_TRACE, DataFlowInfoFactory.EMPTY);
|
||||
PropertyAccessorDescriptor propertyAccessor = isGetter
|
||||
? propertyDescriptor.getGetter()
|
||||
: propertyDescriptor.getSetter();
|
||||
|
||||
Reference in New Issue
Block a user