@Override public void visitJetFile(@NotNull JetFile file) { MutablePackageFragmentDescriptor packageFragment = getOrCreatePackageFragmentForFile(file); c.getPackageFragments().put(file, packageFragment); c.addFile(file); PackageViewDescriptor packageView = packageFragment.getContainingDeclaration().getPackage(packageFragment.getFqName()); ChainedScope rootPlusPackageScope = new ChainedScope( packageView, "Root scope for " + file, packageView.getMemberScope(), outerScope); WriteThroughScope packageScope = new WriteThroughScope( rootPlusPackageScope, packageFragment.getMemberScope(), new TraceBasedRedeclarationHandler(trace), "package in file " + file.getName()); packageScope.changeLockLevel(WritableScope.LockLevel.BOTH); c.getFileScopes().put(file, packageScope); if (file.isScript()) { scriptHeaderResolver.processScriptHierarchy(c, file.getScript(), packageScope); } prepareForDeferredCall(packageScope, packageFragment, file); }
private void resolveAnonymousInitializers() { for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) { resolveAnonymousInitializers(entry.getKey(), entry.getValue()); } for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> entry : context.getObjects().entrySet()) { resolveAnonymousInitializers(entry.getKey(), entry.getValue()); } }
private void resolveDelegationSpecifierLists() { // TODO : Make sure the same thing is not initialized twice for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) { resolveDelegationSpecifierList(entry.getKey(), entry.getValue()); } for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> entry : context.getObjects().entrySet()) { resolveDelegationSpecifierList(entry.getKey(), entry.getValue()); } }
private void resolvePropertyDeclarationBodies() { // Member properties Set<JetProperty> processed = Sets.newHashSet(); for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) { JetClass jetClass = entry.getKey(); if (!context.completeAnalysisNeeded(jetClass)) continue; MutableClassDescriptor classDescriptor = entry.getValue(); for (JetProperty property : jetClass.getProperties()) { final PropertyDescriptor propertyDescriptor = this.context.getProperties().get(property); assert propertyDescriptor != null; computeDeferredType(propertyDescriptor.getReturnType()); JetExpression initializer = property.getInitializer(); if (initializer != null) { ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); if (primaryConstructor != null) { JetScope declaringScopeForPropertyInitializer = this.context.getDeclaringScopes().get(property); resolvePropertyInitializer( property, propertyDescriptor, initializer, declaringScopeForPropertyInitializer); } } resolvePropertyAccessors(property, propertyDescriptor); processed.add(property); } } // Top-level properties & properties of objects for (Map.Entry<JetProperty, PropertyDescriptor> entry : this.context.getProperties().entrySet()) { JetProperty property = entry.getKey(); if (!context.completeAnalysisNeeded(property)) continue; if (processed.contains(property)) continue; final PropertyDescriptor propertyDescriptor = entry.getValue(); computeDeferredType(propertyDescriptor.getReturnType()); JetScope declaringScope = this.context.getDeclaringScopes().get(property); JetExpression initializer = property.getInitializer(); if (initializer != null) { resolvePropertyInitializer(property, propertyDescriptor, initializer, declaringScope); } resolvePropertyAccessors(property, propertyDescriptor); } }
private void detectAndDisconnectLoops(@NotNull TopDownAnalysisContext c) { // Loop detection and disconnection List<Runnable> tasks = new ArrayList<Runnable>(); for (final MutableClassDescriptorLite klass : c.getClassesTopologicalOrder()) { for (final JetType supertype : klass.getSupertypes()) { ClassifierDescriptor supertypeDescriptor = supertype.getConstructor().getDeclarationDescriptor(); if (supertypeDescriptor instanceof MutableClassDescriptorLite) { MutableClassDescriptorLite superclass = (MutableClassDescriptorLite) supertypeDescriptor; if (isReachable(superclass, klass, new HashSet<ClassDescriptor>())) { tasks.add( new Runnable() { @Override public void run() { klass.getSupertypes().remove(supertype); } }); reportCyclicInheritanceHierarchyError(trace, klass, superclass); } } } } for (Runnable task : tasks) { task.run(); } }
@Override public void visitClassObject(@NotNull JetClassObject classObject) { JetObjectDeclaration objectDeclaration = classObject.getObjectDeclaration(); DeclarationDescriptor container = owner.getOwnerForChildren(); MutableClassDescriptor classObjectDescriptor = createClassDescriptorForSingleton( objectDeclaration, getClassObjectName(container.getName()), ClassKind.CLASS_OBJECT); PackageLikeBuilder.ClassObjectStatus status = isEnumEntry(container) || isObject(container) || c.getTopDownAnalysisParameters().isDeclaredLocally() ? PackageLikeBuilder.ClassObjectStatus.NOT_ALLOWED : owner.setClassObjectDescriptor(classObjectDescriptor); switch (status) { case DUPLICATE: trace.report(MANY_CLASS_OBJECTS.on(classObject)); break; case NOT_ALLOWED: trace.report(CLASS_OBJECT_NOT_ALLOWED.on(classObject)); break; case OK: // Everything is OK so no errors to trace. break; } }
@NotNull private MutableClassDescriptor createClassDescriptorForClass( @NotNull JetClass klass, @NotNull DeclarationDescriptor containingDeclaration) { ClassKind kind = getClassKind(klass); // Kind check is needed in order to not consider enums as inner in any case // (otherwise it would be impossible to create a class object in the enum) boolean isInner = kind == ClassKind.CLASS && klass.isInner(); MutableClassDescriptor mutableClassDescriptor = new MutableClassDescriptor( containingDeclaration, outerScope, kind, isInner, JetPsiUtil.safeName(klass.getName())); c.getClasses().put(klass, mutableClassDescriptor); trace.record( FQNAME_TO_CLASS_DESCRIPTOR, JetPsiUtil.getUnsafeFQName(klass), mutableClassDescriptor); createClassObjectForEnumClass(mutableClassDescriptor); JetScope classScope = mutableClassDescriptor.getScopeForMemberDeclarationResolution(); prepareForDeferredCall(classScope, mutableClassDescriptor, klass); return mutableClassDescriptor; }
private List<MutableClassDescriptorLite> topologicallySortClassesAndObjects( @NotNull TopDownAnalysisContext c) { // A topsort is needed only for better diagnostics: // edges that get removed to disconnect loops are more reasonable in this case //noinspection unchecked return DFS.topologicalOrder( (Iterable) c.getClasses().values(), new DFS.Neighbors<MutableClassDescriptorLite>() { @NotNull @Override public Iterable<MutableClassDescriptorLite> getNeighbors( MutableClassDescriptorLite current) { List<MutableClassDescriptorLite> result = Lists.newArrayList(); for (JetType supertype : current.getSupertypes()) { DeclarationDescriptor declarationDescriptor = supertype.getConstructor().getDeclarationDescriptor(); if (declarationDescriptor instanceof MutableClassDescriptorLite) { MutableClassDescriptorLite classDescriptor = (MutableClassDescriptorLite) declarationDescriptor; result.add(classDescriptor); } } return result; } }); }
public void process( @NotNull TopDownAnalysisContext c, @NotNull JetScope outerScope, @NotNull PackageLikeBuilder owner, @NotNull Collection<? extends PsiElement> declarations) { { // TODO: Very temp code - main goal is to remove recursion from // collectPackageFragmentsAndClassifiers Queue<JetDeclarationContainer> forDeferredResolve = new LinkedList<JetDeclarationContainer>(); forDeferredResolve.addAll( collectPackageFragmentsAndClassifiers(c, outerScope, owner, declarations)); while (!forDeferredResolve.isEmpty()) { JetDeclarationContainer declarationContainer = forDeferredResolve.poll(); assert declarationContainer != null; DeclarationDescriptor descriptorForDeferredResolve = c.forDeferredResolver.get(declarationContainer); JetScope scope = c.normalScope.get(declarationContainer); // Even more temp code if (descriptorForDeferredResolve instanceof MutableClassDescriptorLite) { forDeferredResolve.addAll( collectPackageFragmentsAndClassifiers( c, scope, ((MutableClassDescriptorLite) descriptorForDeferredResolve).getBuilder(), declarationContainer.getDeclarations())); } else if (descriptorForDeferredResolve instanceof MutablePackageFragmentDescriptor) { forDeferredResolve.addAll( collectPackageFragmentsAndClassifiers( c, scope, ((MutablePackageFragmentDescriptor) descriptorForDeferredResolve).getBuilder(), declarationContainer.getDeclarations())); } else { assert false; } } } importsResolver.processTypeImports(c); createTypeConstructors( c); // create type constructors for classes and generic parameters, supertypes are not // filled in resolveTypesInClassHeaders( c); // Generic bounds and types in supertype lists (no expressions or constructor // resolution) c.setClassesTopologicalOrder(topologicallySortClassesAndObjects(c)); // Detect and disconnect all loops in the hierarchy detectAndDisconnectLoops(c); }
private void resolveTypesInClassHeaders(@NotNull TopDownAnalysisContext c) { for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry : c.getClasses().entrySet()) { JetClassOrObject classOrObject = entry.getKey(); if (classOrObject instanceof JetClass) { ClassDescriptorWithResolutionScopes descriptor = entry.getValue(); //noinspection unchecked descriptorResolver.resolveGenericBounds( (JetClass) classOrObject, descriptor, descriptor.getScopeForClassHeaderResolution(), (List) descriptor.getTypeConstructor().getParameters(), trace); } } for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry : c.getClasses().entrySet()) { descriptorResolver.resolveSupertypesForMutableClassDescriptor( entry.getKey(), (MutableClassDescriptor) entry.getValue(), trace); } }
private void resolvePrimaryConstructorParameters() { for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) { JetClass klass = entry.getKey(); MutableClassDescriptor classDescriptor = entry.getValue(); ConstructorDescriptor unsubstitutedPrimaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); if (unsubstitutedPrimaryConstructor != null) { checkDefaultParameterValues( klass.getPrimaryConstructorParameters(), unsubstitutedPrimaryConstructor.getValueParameters(), classDescriptor.getScopeForInitializers()); } } }
@NotNull private MutableClassDescriptor createClassDescriptorForSingleton( @NotNull JetClassOrObject declaration, @NotNull Name name, @NotNull ClassKind kind) { MutableClassDescriptor descriptor = new MutableClassDescriptor(owner.getOwnerForChildren(), outerScope, kind, false, name); prepareForDeferredCall( descriptor.getScopeForMemberDeclarationResolution(), descriptor, declaration); createPrimaryConstructorForObject(declaration, descriptor); trace.record(BindingContext.CLASS, declaration, descriptor); c.getClasses().put(declaration, descriptor); return descriptor; }
private void createTypeConstructors(@NotNull TopDownAnalysisContext c) { for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry : c.getClasses().entrySet()) { JetClassOrObject classOrObject = entry.getKey(); MutableClassDescriptor descriptor = (MutableClassDescriptor) entry.getValue(); if (classOrObject instanceof JetClass) { descriptorResolver.resolveMutableClassDescriptor( (JetClass) classOrObject, descriptor, trace); } else if (classOrObject instanceof JetObjectDeclaration) { descriptor.setModality(Modality.FINAL); descriptor.setVisibility( resolveVisibilityFromModifiers(classOrObject, getDefaultClassVisibility(descriptor))); descriptor.setTypeParameterDescriptors(Collections.<TypeParameterDescriptor>emptyList()); } descriptor.createTypeConstructor(); ClassKind kind = descriptor.getKind(); if (kind == ClassKind.ENUM_ENTRY || kind == ClassKind.OBJECT || kind == ClassKind.ENUM_CLASS) { MutableClassDescriptorLite classObject = descriptor.getClassObjectDescriptor(); assert classObject != null : "Enum entries and named objects should have class objects: " + classOrObject.getText(); JetType supertype; if (kind == ClassKind.ENUM_CLASS) { supertype = KotlinBuiltIns.getInstance().getAnyType(); } else { // This is a clever hack: each enum entry and object declaration (i.e. singleton) has a // synthetic class object. // We make this class object inherit from the singleton here, thus allowing to use the // singleton's class object where // the instance of the singleton is applicable. Effectively all members of the singleton // would be present in its class // object as fake overrides, so you can access them via standard class object notation: // ObjectName.memberName() supertype = descriptor.getDefaultType(); } classObject.setSupertypes(Collections.singleton(supertype)); classObject.createTypeConstructor(); } } }
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 JetScope makeScopeForPropertyAccessor( @NotNull JetPropertyAccessor accessor, PropertyDescriptor propertyDescriptor) { JetScope declaringScope = context.getDeclaringScopes().get(accessor); JetScope propertyDeclarationInnerScope = descriptorResolver.getPropertyDeclarationInnerScope( declaringScope, propertyDescriptor, propertyDescriptor.getTypeParameters(), propertyDescriptor.getReceiverParameter(), trace); WritableScope accessorScope = new WritableScopeImpl( propertyDeclarationInnerScope, declaringScope.getContainingDeclaration(), new TraceBasedRedeclarationHandler(trace)) .setDebugName("Accessor scope"); accessorScope.changeLockLevel(WritableScope.LockLevel.READING); return accessorScope; }
private void resolveFunctionBody( @NotNull BindingTrace trace, @NotNull JetDeclarationWithBody function, @NotNull FunctionDescriptor functionDescriptor, @NotNull JetScope declaringScope) { if (!context.completeAnalysisNeeded(function)) return; JetExpression bodyExpression = function.getBodyExpression(); JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(declaringScope, functionDescriptor, trace); if (bodyExpression != null) { expressionTypingServices.checkFunctionReturnType( functionInnerScope, function, functionDescriptor, trace); } List<JetParameter> valueParameters = function.getValueParameters(); List<ValueParameterDescriptor> valueParameterDescriptors = functionDescriptor.getValueParameters(); checkDefaultParameterValues(valueParameters, valueParameterDescriptors, functionInnerScope); assert functionDescriptor.getReturnType() != null; }
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 resolveDelegationSpecifierList( final JetClassOrObject jetClass, final MutableClassDescriptor descriptor) { if (!context.completeAnalysisNeeded(jetClass)) return; final ConstructorDescriptor primaryConstructor = descriptor.getUnsubstitutedPrimaryConstructor(); final JetScope scopeForConstructor = primaryConstructor == null ? null : FunctionDescriptorUtil.getFunctionInnerScope( descriptor.getScopeForSupertypeResolution(), primaryConstructor, trace); final ExpressionTypingServices typeInferrer = expressionTypingServices; // TODO : flow final Map<JetTypeReference, JetType> supertypes = Maps.newLinkedHashMap(); JetVisitorVoid visitor = new JetVisitorVoid() { private void recordSupertype(JetTypeReference typeReference, JetType supertype) { if (supertype == null) return; supertypes.put(typeReference, supertype); } @Override public void visitDelegationByExpressionSpecifier( JetDelegatorByExpressionSpecifier specifier) { if (descriptor.getKind() == ClassKind.TRAIT) { 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.TRAIT) { trace.report(DELEGATION_NOT_TO_TRAIT.on(specifier.getTypeReference())); } } } JetExpression delegateExpression = specifier.getDelegateExpression(); if (delegateExpression != null) { JetScope scope = scopeForConstructor == null ? descriptor.getScopeForMemberResolution() : scopeForConstructor; JetType type = typeInferrer.getType(scope, delegateExpression, NO_EXPECTED_TYPE, trace); if (type != null && supertype != null && !JetTypeChecker.INSTANCE.isSubtypeOf(type, supertype)) { trace.report(TYPE_MISMATCH.on(delegateExpression, supertype, type)); } } } @Override public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) { JetValueArgumentList valueArgumentList = call.getValueArgumentList(); PsiElement elementToMark = valueArgumentList == null ? call : valueArgumentList; if (descriptor.getKind() == ClassKind.TRAIT) { trace.report(SUPERTYPE_INITIALIZED_IN_TRAIT.on(elementToMark)); } JetTypeReference typeReference = call.getTypeReference(); if (typeReference == null) return; if (descriptor.getUnsubstitutedPrimaryConstructor() == null) { assert descriptor.getKind() == ClassKind.TRAIT; return; } OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveFunctionCall( trace, scopeForConstructor, CallMaker.makeCall(ReceiverDescriptor.NO_RECEIVER, null, call), NO_EXPECTED_TYPE, DataFlowInfo.EMPTY); if (results.isSuccess()) { JetType supertype = results.getResultingDescriptor().getReturnType(); recordSupertype(typeReference, supertype); ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype); if (classDescriptor != null) { if (classDescriptor.getKind() == ClassKind.TRAIT) { trace.report(CONSTRUCTOR_IN_TRAIT.on(elementToMark)); } } } else { recordSupertype( typeReference, trace.getBindingContext().get(BindingContext.TYPE, typeReference)); } } @Override public void visitDelegationToSuperClassSpecifier(JetDelegatorToSuperClass specifier) { JetTypeReference typeReference = specifier.getTypeReference(); JetType supertype = trace.getBindingContext().get(BindingContext.TYPE, typeReference); recordSupertype(typeReference, supertype); if (supertype == null) return; ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype); if (classDescriptor == null) return; if (descriptor.getKind() != ClassKind.TRAIT && classDescriptor.hasConstructors() && !ErrorUtils.isError(classDescriptor.getTypeConstructor()) && classDescriptor.getKind() != ClassKind.TRAIT) { boolean hasConstructorWithoutParams = false; for (ConstructorDescriptor constructor : classDescriptor.getConstructors()) { if (constructor.getValueParameters().isEmpty()) { hasConstructorWithoutParams = true; } } if (!hasConstructorWithoutParams) { trace.report(SUPERTYPE_NOT_INITIALIZED.on(specifier)); } else { trace.report(SUPERTYPE_NOT_INITIALIZED_DEFAULT.on(specifier)); } } } @Override public void visitDelegationToThisCall(JetDelegatorToThisCall thisCall) { throw new IllegalStateException("This-calls should be prohibited by the parser"); } @Override public void visitJetElement(JetElement element) { throw new UnsupportedOperationException(element.getText() + " : " + element); } }; for (JetDelegationSpecifier delegationSpecifier : jetClass.getDelegationSpecifiers()) { delegationSpecifier.accept(visitor); } Set<TypeConstructor> parentEnum = Collections.emptySet(); if (jetClass instanceof JetEnumEntry) { parentEnum = Collections.singleton( ((ClassDescriptor) descriptor.getContainingDeclaration().getContainingDeclaration()) .getTypeConstructor()); } checkSupertypeList(descriptor, supertypes, parentEnum); }