private void computeDeferredTypes() { Collection<Box<DeferredType>> deferredTypes = trace.getKeys(DEFERRED_TYPE); if (deferredTypes != null) { // +1 is a work around agains new Queue(0).addLast(...) bug // stepan.koltsov@ 2011-11-21 final Queue<DeferredType> queue = new Queue<DeferredType>(deferredTypes.size() + 1); trace.addHandler( DEFERRED_TYPE, new ObservableBindingTrace.RecordHandler<Box<DeferredType>, Boolean>() { @Override public void handleRecord( WritableSlice<Box<DeferredType>, Boolean> deferredTypeKeyDeferredTypeWritableSlice, Box<DeferredType> key, Boolean value) { queue.addLast(key.getData()); } }); for (Box<DeferredType> deferredType : deferredTypes) { queue.addLast(deferredType.getData()); } while (!queue.isEmpty()) { DeferredType deferredType = queue.pullFirst(); if (!deferredType.isComputed()) { try { deferredType.getActualType(); // to compute } catch (ReenteringLazyValueComputationException e) { // A problem should be reported while computing the type } } } } }
// allowedFinalSupertypes typically contains a enum type of which supertypeOwner is an entry private void checkSupertypeList( @NotNull MutableClassDescriptor supertypeOwner, @NotNull Map<JetTypeReference, JetType> supertypes, Set<TypeConstructor> allowedFinalSupertypes) { Set<TypeConstructor> typeConstructors = Sets.newHashSet(); boolean classAppeared = false; for (Map.Entry<JetTypeReference, JetType> entry : supertypes.entrySet()) { JetTypeReference typeReference = entry.getKey(); JetType supertype = entry.getValue(); ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype); if (classDescriptor != null) { if (classDescriptor.getKind() != ClassKind.TRAIT) { if (classAppeared) { trace.report(MANY_CLASSES_IN_SUPERTYPE_LIST.on(typeReference)); } else { classAppeared = true; } } } else { trace.report(SUPERTYPE_NOT_A_CLASS_OR_TRAIT.on(typeReference)); } TypeConstructor constructor = supertype.getConstructor(); if (!typeConstructors.add(constructor)) { trace.report(SUPERTYPE_APPEARS_TWICE.on(typeReference)); } if (constructor.isSealed() && !allowedFinalSupertypes.contains(constructor)) { trace.report(FINAL_SUPERTYPE.on(typeReference)); } } }
public void resolvePropertyDelegate( @NotNull DataFlowInfo outerDataFlowInfo, @NotNull JetProperty jetProperty, @NotNull PropertyDescriptor propertyDescriptor, @NotNull JetExpression delegateExpression, @NotNull LexicalScope parentScopeForAccessor, @NotNull LexicalScope propertyScope) { JetPropertyAccessor getter = jetProperty.getGetter(); if (getter != null && getter.hasBody()) { trace.report(ACCESSOR_FOR_DELEGATED_PROPERTY.on(getter)); } JetPropertyAccessor setter = jetProperty.getSetter(); if (setter != null && setter.hasBody()) { trace.report(ACCESSOR_FOR_DELEGATED_PROPERTY.on(setter)); } LexicalScope propertyDeclarationInnerScope = JetScopeUtils.getPropertyDeclarationInnerScopeForInitializer( propertyDescriptor, propertyScope, propertyDescriptor.getTypeParameters(), null, trace); LexicalScope accessorScope = JetScopeUtils.makeScopeForPropertyAccessor( propertyDescriptor, parentScopeForAccessor, trace); JetType delegateType = delegatedPropertyResolver.resolveDelegateExpression( delegateExpression, jetProperty, propertyDescriptor, propertyDeclarationInnerScope, accessorScope, trace, outerDataFlowInfo); delegatedPropertyResolver.resolveDelegatedPropertyGetMethod( propertyDescriptor, delegateExpression, delegateType, trace, accessorScope); if (jetProperty.isVar()) { delegatedPropertyResolver.resolveDelegatedPropertySetMethod( propertyDescriptor, delegateExpression, delegateType, trace, accessorScope); } delegatedPropertyResolver.resolveDelegatedPropertyPDMethod( propertyDescriptor, delegateExpression, delegateType, trace, accessorScope); }
@Nullable private ConstructorDescriptor getDelegatedConstructor( @NotNull ConstructorDescriptor constructor) { ResolvedCall<ConstructorDescriptor> call = trace.get(CONSTRUCTOR_RESOLVED_DELEGATION_CALL, constructor); return call == null || !call.getStatus().isSuccess() ? null : call.getResultingDescriptor().getOriginal(); }
public void resolveAnonymousInitializer( @NotNull DataFlowInfo outerDataFlowInfo, @NotNull JetClassInitializer anonymousInitializer, @NotNull ClassDescriptorWithResolutionScopes classDescriptor) { LexicalScope scopeForInitializers = classDescriptor.getScopeForInitializerResolution(); if (!classDescriptor.getConstructors().isEmpty()) { JetExpression body = anonymousInitializer.getBody(); if (body != null) { expressionTypingServices.getType( scopeForInitializers, body, NO_EXPECTED_TYPE, outerDataFlowInfo, trace); } processModifiersOnInitializer(anonymousInitializer, scopeForInitializers); } else { trace.report(ANONYMOUS_INITIALIZER_IN_TRAIT.on(anonymousInitializer)); processModifiersOnInitializer(anonymousInitializer, scopeForInitializers); } }
private void reportEachConstructorOnCycle(@NotNull ConstructorDescriptor startConstructor) { ConstructorDescriptor currentConstructor = startConstructor; do { PsiElement constructorToReport = DescriptorToSourceUtils.descriptorToDeclaration(currentConstructor); if (constructorToReport != null) { JetConstructorDelegationCall call = ((JetSecondaryConstructor) constructorToReport).getDelegationCall(); assert call.getCalleeExpression() != null : "Callee expression of delegation call should not be null on cycle as there should be explicit 'this' calls"; trace.report(CYCLIC_CONSTRUCTOR_DELEGATION_CALL.on(call.getCalleeExpression())); } currentConstructor = getDelegatedConstructor(currentConstructor); assert currentConstructor != null : "Delegated constructor should not be null in cycle"; } while (startConstructor != currentConstructor); }
private void resolveAnonymousInitializers( JetClassOrObject jetClassOrObject, MutableClassDescriptor classDescriptor) { if (!context.completeAnalysisNeeded(jetClassOrObject)) return; List<JetClassInitializer> anonymousInitializers = jetClassOrObject.getAnonymousInitializers(); if (classDescriptor.getUnsubstitutedPrimaryConstructor() != null) { ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); assert primaryConstructor != null; final JetScope scopeForInitializers = classDescriptor.getScopeForInitializers(); for (JetClassInitializer anonymousInitializer : anonymousInitializers) { expressionTypingServices.getType( scopeForInitializers, anonymousInitializer.getBody(), NO_EXPECTED_TYPE, trace); } } else { for (JetClassInitializer anonymousInitializer : anonymousInitializers) { trace.report(ANONYMOUS_INITIALIZER_WITHOUT_CONSTRUCTOR.on(anonymousInitializer)); } } }
private void resolveSecondaryConstructorBody( JetSecondaryConstructor declaration, final ConstructorDescriptor descriptor) { if (!context.completeAnalysisNeeded(declaration)) return; MutableClassDescriptor classDescriptor = (MutableClassDescriptor) descriptor.getContainingDeclaration(); final JetScope scopeForSupertypeInitializers = FunctionDescriptorUtil.getFunctionInnerScope( classDescriptor.getScopeForSupertypeResolution(), descriptor, trace); // contains only constructor parameters final JetScope scopeForConstructorBody = FunctionDescriptorUtil.getFunctionInnerScope( classDescriptor.getScopeForInitializers(), descriptor, trace); // contains members & backing fields final DataFlowInfo dataFlowInfo = DataFlowInfo.EMPTY; // TODO: dataFlowInfo PsiElement nameElement = declaration.getNameNode().getPsi(); if (classDescriptor.getUnsubstitutedPrimaryConstructor() == null) { trace.report(SECONDARY_CONSTRUCTOR_BUT_NO_PRIMARY.on(nameElement)); } else { List<JetDelegationSpecifier> initializers = declaration.getInitializers(); if (initializers.isEmpty()) { trace.report(SECONDARY_CONSTRUCTOR_NO_INITIALIZER_LIST.on(nameElement)); } else { initializers .get(0) .accept( new JetVisitorVoid() { @Override public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) { JetTypeReference typeReference = call.getTypeReference(); if (typeReference != null) { callResolver.resolveFunctionCall( trace, scopeForSupertypeInitializers, CallMaker.makeCall(ReceiverDescriptor.NO_RECEIVER, null, call), NO_EXPECTED_TYPE, dataFlowInfo); } } @Override public void visitDelegationToThisCall(JetDelegatorToThisCall call) { // TODO : check that there's no recursion in this() calls // TODO : check: if a this() call is present, no other initializers are allowed ClassDescriptor classDescriptor = descriptor.getContainingDeclaration(); callResolver.resolveFunctionCall( trace, scopeForSupertypeInitializers, CallMaker.makeCall(ReceiverDescriptor.NO_RECEIVER, null, call), NO_EXPECTED_TYPE, dataFlowInfo); // call.getThisReference(), // classDescriptor, // classDescriptor.getDefaultType(), // call); // trace.getErrorHandler().genericError(call.getNode(), // "this-calls are not supported"); } @Override public void visitDelegationByExpressionSpecifier( JetDelegatorByExpressionSpecifier specifier) { trace.report(BY_IN_SECONDARY_CONSTRUCTOR.on(specifier)); } @Override public void visitDelegationToSuperClassSpecifier( JetDelegatorToSuperClass specifier) { trace.report(INITIALIZER_WITH_NO_ARGUMENTS.on(specifier)); } @Override public void visitDelegationSpecifier(JetDelegationSpecifier specifier) { throw new IllegalStateException(); } }); for (int i = 1, initializersSize = initializers.size(); i < initializersSize; i++) { JetDelegationSpecifier initializer = initializers.get(i); trace.report(MANY_CALLS_TO_THIS.on(initializer)); } } } JetExpression bodyExpression = declaration.getBodyExpression(); if (bodyExpression != null) { expressionTypingServices.checkFunctionReturnType( scopeForConstructorBody, declaration, descriptor, JetStandardClasses.getUnitType(), trace); } checkDefaultParameterValues( declaration.getValueParameters(), descriptor.getValueParameters(), scopeForConstructorBody); }
private void checkSupertypeList( @NotNull ClassDescriptor supertypeOwner, @NotNull Map<JetTypeReference, JetType> supertypes, @NotNull JetClassOrObject jetClass) { Set<TypeConstructor> allowedFinalSupertypes = getAllowedFinalSupertypes(supertypeOwner, jetClass); Set<TypeConstructor> typeConstructors = Sets.newHashSet(); boolean classAppeared = false; for (Map.Entry<JetTypeReference, JetType> entry : supertypes.entrySet()) { JetTypeReference typeReference = entry.getKey(); JetType supertype = entry.getValue(); boolean addSupertype = true; ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype); if (classDescriptor != null) { if (ErrorUtils.isError(classDescriptor)) continue; if (classDescriptor.getKind() != ClassKind.INTERFACE) { if (supertypeOwner.getKind() == ClassKind.ENUM_CLASS) { trace.report(CLASS_IN_SUPERTYPE_FOR_ENUM.on(typeReference)); addSupertype = false; } else if (supertypeOwner.getKind() == ClassKind.INTERFACE && !classAppeared && !TypesPackage.isDynamic(supertype) /* avoid duplicate diagnostics */) { trace.report(TRAIT_WITH_SUPERCLASS.on(typeReference)); addSupertype = false; } if (classAppeared) { trace.report(MANY_CLASSES_IN_SUPERTYPE_LIST.on(typeReference)); } else { classAppeared = true; } } } else { trace.report(SUPERTYPE_NOT_A_CLASS_OR_TRAIT.on(typeReference)); } TypeConstructor constructor = supertype.getConstructor(); if (addSupertype && !typeConstructors.add(constructor)) { trace.report(SUPERTYPE_APPEARS_TWICE.on(typeReference)); } if (DescriptorUtils.isSingleton(classDescriptor)) { trace.report(SINGLETON_IN_SUPERTYPE.on(typeReference)); } else if (constructor.isFinal() && !allowedFinalSupertypes.contains(constructor)) { if (classDescriptor.getModality() == Modality.SEALED) { DeclarationDescriptor containingDescriptor = supertypeOwner.getContainingDeclaration(); while (containingDescriptor != null && containingDescriptor != classDescriptor) { containingDescriptor = containingDescriptor.getContainingDeclaration(); } if (containingDescriptor == null) { trace.report(SEALED_SUPERTYPE.on(typeReference)); } else { trace.report(SEALED_SUPERTYPE_IN_LOCAL_CLASS.on(typeReference)); } } else { trace.report(FINAL_SUPERTYPE.on(typeReference)); } } } }
public void resolveDelegationSpecifierList( @NotNull final DataFlowInfo outerDataFlowInfo, @NotNull JetClassOrObject jetClass, @NotNull final ClassDescriptor descriptor, @Nullable final ConstructorDescriptor primaryConstructor, @NotNull LexicalScope scopeForSupertypeResolution, @NotNull final LexicalScope scopeForMemberResolution) { final LexicalScope scopeForConstructor = primaryConstructor == null ? null : FunctionDescriptorUtil.getFunctionInnerScope( scopeForSupertypeResolution, primaryConstructor, trace); final ExpressionTypingServices typeInferrer = expressionTypingServices; // TODO : flow final Map<JetTypeReference, JetType> supertypes = Maps.newLinkedHashMap(); final ResolvedCall<?>[] primaryConstructorDelegationCall = new ResolvedCall[1]; JetVisitorVoid visitor = new JetVisitorVoid() { private void recordSupertype(JetTypeReference typeReference, JetType supertype) { if (supertype == null) return; supertypes.put(typeReference, supertype); } @Override public void visitDelegationByExpressionSpecifier( @NotNull JetDelegatorByExpressionSpecifier specifier) { if (descriptor.getKind() == ClassKind.INTERFACE) { trace.report(DELEGATION_IN_TRAIT.on(specifier)); } JetType supertype = trace.getBindingContext().get(BindingContext.TYPE, specifier.getTypeReference()); recordSupertype(specifier.getTypeReference(), supertype); if (supertype != null) { DeclarationDescriptor declarationDescriptor = supertype.getConstructor().getDeclarationDescriptor(); if (declarationDescriptor instanceof ClassDescriptor) { ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; if (classDescriptor.getKind() != ClassKind.INTERFACE) { trace.report(DELEGATION_NOT_TO_TRAIT.on(specifier.getTypeReference())); } } } JetExpression delegateExpression = specifier.getDelegateExpression(); if (delegateExpression != null) { LexicalScope scope = scopeForConstructor == null ? scopeForMemberResolution : scopeForConstructor; JetType expectedType = supertype != null ? supertype : NO_EXPECTED_TYPE; typeInferrer.getType( scope, delegateExpression, expectedType, outerDataFlowInfo, trace); } if (primaryConstructor == null) { trace.report( UNSUPPORTED.on( specifier, "Delegation without primary constructor is not supported")); } } @Override public void visitDelegationToSuperCallSpecifier(@NotNull JetDelegatorToSuperCall call) { JetValueArgumentList valueArgumentList = call.getValueArgumentList(); PsiElement elementToMark = valueArgumentList == null ? call : valueArgumentList; if (descriptor.getKind() == ClassKind.INTERFACE) { trace.report(SUPERTYPE_INITIALIZED_IN_TRAIT.on(elementToMark)); } JetTypeReference typeReference = call.getTypeReference(); if (typeReference == null) return; if (primaryConstructor == null) { if (descriptor.getKind() != ClassKind.INTERFACE) { trace.report(SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR.on(call)); } recordSupertype( typeReference, trace.getBindingContext().get(BindingContext.TYPE, typeReference)); return; } OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveFunctionCall( trace, scopeForConstructor, CallMaker.makeCall(ReceiverValue.NO_RECEIVER, null, call), NO_EXPECTED_TYPE, outerDataFlowInfo, false); if (results.isSuccess()) { JetType supertype = results.getResultingDescriptor().getReturnType(); recordSupertype(typeReference, supertype); ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype); if (classDescriptor != null) { // allow only one delegating constructor if (primaryConstructorDelegationCall[0] == null) { primaryConstructorDelegationCall[0] = results.getResultingCall(); } else { primaryConstructorDelegationCall[0] = null; } } // Recording type info for callee to use later in JetObjectLiteralExpression trace.record(PROCESSED, call.getCalleeExpression(), true); trace.record( EXPRESSION_TYPE_INFO, call.getCalleeExpression(), TypeInfoFactoryPackage.noTypeInfo( results.getResultingCall().getDataFlowInfoForArguments().getResultInfo())); } else { recordSupertype( typeReference, trace.getBindingContext().get(BindingContext.TYPE, typeReference)); } } @Override public void visitDelegationToSuperClassSpecifier( @NotNull JetDelegatorToSuperClass specifier) { JetTypeReference typeReference = specifier.getTypeReference(); JetType supertype = trace.getBindingContext().get(BindingContext.TYPE, typeReference); recordSupertype(typeReference, supertype); if (supertype == null) return; ClassDescriptor superClass = TypeUtils.getClassDescriptor(supertype); if (superClass == null) return; if (superClass.getKind().isSingleton()) { // A "singleton in supertype" diagnostic will be reported later return; } if (descriptor.getKind() != ClassKind.INTERFACE && descriptor.getUnsubstitutedPrimaryConstructor() != null && superClass.getKind() != ClassKind.INTERFACE && !superClass.getConstructors().isEmpty() && !ErrorUtils.isError(superClass)) { trace.report(SUPERTYPE_NOT_INITIALIZED.on(specifier)); } } @Override public void visitJetElement(@NotNull JetElement element) { throw new UnsupportedOperationException(element.getText() + " : " + element); } }; for (JetDelegationSpecifier delegationSpecifier : jetClass.getDelegationSpecifiers()) { delegationSpecifier.accept(visitor); } if (DescriptorUtils.isAnnotationClass(descriptor) && jetClass.getDelegationSpecifierList() != null) { trace.report(SUPERTYPES_FOR_ANNOTATION_CLASS.on(jetClass.getDelegationSpecifierList())); } if (primaryConstructorDelegationCall[0] != null && primaryConstructor != null) { recordConstructorDelegationCall( trace, primaryConstructor, primaryConstructorDelegationCall[0]); } checkSupertypeList(descriptor, supertypes, jetClass); }