diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/Annotated.java b/idea/src/org/jetbrains/jet/lang/descriptors/Annotated.java deleted file mode 100644 index c956ec791c5c5d763815479e813e93f02c27b531..0000000000000000000000000000000000000000 --- a/idea/src/org/jetbrains/jet/lang/descriptors/Annotated.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.jetbrains.jet.lang.descriptors; - -import java.util.List; - -/** - * @author abreslav - */ -public interface Annotated { - List getAnnotations(); -} diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/AnnotatedImpl.java b/idea/src/org/jetbrains/jet/lang/descriptors/AnnotatedImpl.java deleted file mode 100644 index 2cbe63b1e0ddb929fb542dc9862e3c9089a8b2a8..0000000000000000000000000000000000000000 --- a/idea/src/org/jetbrains/jet/lang/descriptors/AnnotatedImpl.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.jetbrains.jet.lang.descriptors; - -import java.util.List; - -/** - * @author abreslav - */ -public abstract class AnnotatedImpl implements Annotated { - private final List annotations; - - public AnnotatedImpl(List annotations) { - this.annotations = annotations; - } - - @Override - public List getAnnotations() { - return annotations; - } -} diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetDeclarationWithBody.java b/idea/src/org/jetbrains/jet/lang/psi/JetDeclarationWithBody.java index 3bce72ddf0f6fe40d1fda6fd57040206f7404a65..2cd3c48b0dbb924f73a6418117f7856e6bac6137 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetDeclarationWithBody.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetDeclarationWithBody.java @@ -1,6 +1,5 @@ package org.jetbrains.jet.lang.psi; -import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetPropertyAccessor.java b/idea/src/org/jetbrains/jet/lang/psi/JetPropertyAccessor.java index df7e061e3a8674d457cfbe2b96a2488b305f4e9b..b7198394d41d5a0c43ff13bb83ed9fa8a734074b 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetPropertyAccessor.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetPropertyAccessor.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.lang.psi; import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; @@ -70,4 +71,11 @@ public class JetPropertyAccessor extends JetDeclaration implements JetDeclaratio return findChildByClass(JetTypeReference.class); } + public PsiElement getNamePlaceholder() { + PsiElement get = findChildByType(JetTokens.GET_KEYWORD); + if (get != null) { + return get; + } + return findChildByType(JetTokens.SET_KEYWORD); + } } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/BodyResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/BodyResolver.java new file mode 100644 index 0000000000000000000000000000000000000000..7faed993d7d1765b24a1fca6136d0a8ede045122 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/resolve/BodyResolver.java @@ -0,0 +1,702 @@ +package org.jetbrains.jet.lang.resolve; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; +import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.JetSemanticServices; +import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.types.*; +import org.jetbrains.jet.lexer.JetTokens; +import org.jetbrains.jet.util.slicedmap.WritableSlice; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.jetbrains.jet.lang.types.JetTypeInferrer.NO_EXPECTED_TYPE; + +/** +* @author abreslav +*/ +public class BodyResolver { + private final JetSemanticServices semanticServices; + private final ClassDescriptorResolver classDescriptorResolver; + private final BindingTrace trace; + private final BindingTraceAdapter traceForConstructors; + private final BindingTraceAdapter traceForMembers; + private final DeclarationResolver declarationResolver; + private final TypeHierarchyResolver typeHierarchyResolver; + + public BodyResolver(JetSemanticServices semanticServices, @NotNull BindingTrace trace, TypeHierarchyResolver typeHierarchyResolver, DeclarationResolver declarationResolver) { + this.semanticServices = semanticServices; + this.classDescriptorResolver = semanticServices.getClassDescriptorResolver(trace); + this.trace = trace; + this.declarationResolver = declarationResolver; + this.typeHierarchyResolver = typeHierarchyResolver; + + // This allows access to backing fields + this.traceForConstructors = new BindingTraceAdapter(trace).addHandler(BindingContext.REFERENCE_TARGET, new BindingTraceAdapter.RecordHandler() { + @Override + public void handleRecord(WritableSlice slice, JetReferenceExpression expression, DeclarationDescriptor descriptor) { + if (expression instanceof JetSimpleNameExpression) { + JetSimpleNameExpression simpleNameExpression = (JetSimpleNameExpression) expression; + if (simpleNameExpression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) { + if (!BodyResolver.this.trace.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) descriptor)) { + BodyResolver.this.trace.getErrorHandler().genericError(expression.getNode(), "This property does not have a backing field"); + } + } + } + } + }); + + // This tracks access to properties in order to register primary constructor parameters that yield real fields (JET-9) + this.traceForMembers = new BindingTraceAdapter(trace).addHandler(BindingContext.REFERENCE_TARGET, new BindingTraceAdapter.RecordHandler() { + @Override + public void handleRecord(WritableSlice slice, JetReferenceExpression expression, DeclarationDescriptor descriptor) { + if (descriptor instanceof PropertyDescriptor) { + PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; + if (BodyResolver.this.declarationResolver.getPrimaryConstructorParameterProperties().contains(propertyDescriptor)) { + traceForMembers.record(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor); + } + } + } + }); + + } + + + public void resolveBehaviorDeclarationBodies() { + bindOverrides(); + + resolveDelegationSpecifierLists(); + resolveClassAnnotations(); + + resolveAnonymousInitializers(); + resolvePropertyDeclarationBodies(); + + resolveSecondaryConstructorBodies(); + resolveFunctionBodies(); + + checkIfPrimaryConstructorIsNecessary(); + } + + private void bindOverrides() { + for (Map.Entry entry : typeHierarchyResolver.getClasses().entrySet()) { + bindOverridesInAClass(entry.getValue()); + } + for (Map.Entry entry : typeHierarchyResolver.getObjects().entrySet()) { + bindOverridesInAClass(entry.getValue()); + } + } + + protected void bindOverridesInAClass(MutableClassDescriptor classDescriptor) { + + for (FunctionDescriptor declaredFunction : classDescriptor.getFunctions()) { + JetFunction function = (JetFunction) trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, declaredFunction); + assert function != null; + JetModifierList modifierList = function.getModifierList(); + ASTNode overrideNode = modifierList != null ? modifierList.getModifierNode(JetTokens.OVERRIDE_KEYWORD) : null; + boolean hasOverrideModifier = overrideNode != null; + boolean foundError = false; + for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) { + FunctionDescriptor overridden = findFunctionOverridableBy(declaredFunction, supertype); + if (overridden != null) { + if (hasOverrideModifier && !overridden.getModality().isOpen() && !foundError) { + trace.getErrorHandler().genericError(overrideNode, "Method " + overridden.getName() + " in " + overridden.getContainingDeclaration().getName() + " is final and can not be overridden"); + foundError = true; + } + ((FunctionDescriptorImpl) declaredFunction).addOverriddenFunction(overridden); + } + } + if (hasOverrideModifier && declaredFunction.getOverriddenDescriptors().size() == 0) { + trace.getErrorHandler().genericError(overrideNode, "Method " + declaredFunction.getName() + " overrides nothing"); + } + PsiElement nameIdentifier = function.getNameIdentifier(); + if (!hasOverrideModifier && declaredFunction.getOverriddenDescriptors().size() > 0 && nameIdentifier != null) { + FunctionDescriptor overriddenMethod = declaredFunction.getOverriddenDescriptors().iterator().next(); + trace.getErrorHandler().genericError(nameIdentifier.getNode(), + "Method " + declaredFunction.getName() + " overrides method " + overriddenMethod.getName() + " in class " + + overriddenMethod.getContainingDeclaration().getName() + " and needs 'override' modifier"); + } + } + } + + @Nullable + private FunctionDescriptor findFunctionOverridableBy(@NotNull FunctionDescriptor declaredFunction, @NotNull JetType supertype) { + FunctionGroup functionGroup = supertype.getMemberScope().getFunctionGroup(declaredFunction.getName()); + for (FunctionDescriptor functionDescriptor : functionGroup.getFunctionDescriptors()) { + if (FunctionDescriptorUtil.isOverridableBy(semanticServices.getTypeChecker(), functionDescriptor, declaredFunction).isSuccess()) { + return functionDescriptor; + } + } + return null; + } + + private void checkIfPrimaryConstructorIsNecessary() { + for (Map.Entry entry : typeHierarchyResolver.getClasses().entrySet()) { + MutableClassDescriptor classDescriptor = entry.getValue(); + JetClass jetClass = entry.getKey(); + if (classDescriptor.getUnsubstitutedPrimaryConstructor() == null) { + for (PropertyDescriptor propertyDescriptor : classDescriptor.getProperties()) { + if (trace.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)) { + PsiElement nameIdentifier = jetClass.getNameIdentifier(); + if (nameIdentifier != null) { + trace.getErrorHandler().genericError(nameIdentifier.getNode(), + "This class must have a primary constructor, because property " + propertyDescriptor.getName() + " has a backing field"); + } + break; + } + } + } + } + } + + private void resolveDelegationSpecifierLists() { + // TODO : Make sure the same thing is not initialized twice + for (Map.Entry entry : typeHierarchyResolver.getClasses().entrySet()) { + resolveDelegationSpecifierList(entry.getKey(), entry.getValue()); + } + for (Map.Entry entry : typeHierarchyResolver.getObjects().entrySet()) { + resolveDelegationSpecifierList(entry.getKey(), entry.getValue()); + } + } + + private void resolveDelegationSpecifierList(final JetClassOrObject jetClass, final MutableClassDescriptor descriptor) { + final ConstructorDescriptor primaryConstructor = descriptor.getUnsubstitutedPrimaryConstructor(); + final JetScope scopeForConstructor = primaryConstructor == null + ? null + : getInnerScopeForConstructor(primaryConstructor, descriptor.getScopeForMemberResolution(), true); + final JetTypeInferrer.Services typeInferrer = semanticServices.getTypeInferrerServices(traceForConstructors, JetFlowInformationProvider.NONE); // TODO : flow + + final Map 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.getErrorHandler().genericError(specifier.getNode(), "Traits can not use delegation"); + } + JetType supertype = trace.getBindingContext().get(BindingContext.TYPE, specifier.getTypeReference()); + recordSupertype(specifier.getTypeReference(), supertype); + JetExpression delegateExpression = specifier.getDelegateExpression(); + if (delegateExpression != null) { + JetScope scope = scopeForConstructor == null + ? descriptor.getScopeForMemberResolution() + : scopeForConstructor; + JetType type = typeInferrer.getType(scope, delegateExpression, NO_EXPECTED_TYPE); + if (type != null && supertype != null && !semanticServices.getTypeChecker().isSubtypeOf(type, supertype)) { + trace.getErrorHandler().typeMismatch(delegateExpression, supertype, type); + } + } + } + + @Override + public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) { + JetValueArgumentList valueArgumentList = call.getValueArgumentList(); + ASTNode node = valueArgumentList == null ? call.getNode() : valueArgumentList.getNode(); + if (descriptor.getKind() == ClassKind.TRAIT) { + trace.getErrorHandler().genericError(node, "Traits can not initialize supertypes"); + } + JetTypeReference typeReference = call.getTypeReference(); + if (typeReference != null) { + if (descriptor.getUnsubstitutedPrimaryConstructor() != null) { + JetType supertype = typeInferrer.getCallResolver().resolveCall(trace, scopeForConstructor, null, call, NO_EXPECTED_TYPE); + if (supertype != null) { + recordSupertype(typeReference, supertype); + ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype); + if (classDescriptor != null) { + if (classDescriptor.getKind() == ClassKind.TRAIT) { + trace.getErrorHandler().genericError(node, "A trait may not have a constructor"); + } + } + } + else { + recordSupertype(typeReference, trace.getBindingContext().get(BindingContext.TYPE, typeReference)); + } + } + else if (descriptor.getKind() != ClassKind.TRAIT) { + JetType supertype = trace.getBindingContext().get(BindingContext.TYPE, typeReference); + recordSupertype(typeReference, supertype); + + assert valueArgumentList != null; + trace.getErrorHandler().genericError(valueArgumentList.getNode(), + "Class " + JetPsiUtil.safeName(jetClass.getName()) + " must have a constructor in order to be able to initialize supertypes"); + } + } + } + + @Override + public void visitDelegationToSuperClassSpecifier(JetDelegatorToSuperClass specifier) { + JetTypeReference typeReference = specifier.getTypeReference(); + JetType supertype = trace.getBindingContext().get(BindingContext.TYPE, typeReference); + recordSupertype(typeReference, supertype); + if (supertype != null) { + ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype); + if (classDescriptor != null) { + if (descriptor.getKind() != ClassKind.TRAIT) { + if (classDescriptor.hasConstructors() && !ErrorUtils.isError(classDescriptor.getTypeConstructor()) && classDescriptor.getKind() != ClassKind.TRAIT) { + trace.getErrorHandler().genericError(specifier.getNode(), "This type has a constructor, and thus must be initialized here"); + } + } + } + } + } + + @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 parentEnum = Collections.emptySet(); + if (jetClass instanceof JetEnumEntry) { + parentEnum = Collections.singleton(((ClassDescriptor) descriptor.getContainingDeclaration().getContainingDeclaration()).getTypeConstructor()); + } + + checkSupertypeList(descriptor, supertypes, parentEnum); + } + + // allowedFinalSupertypes typically contains a enum type of which supertypeOwner is an entry + private void checkSupertypeList(@NotNull MutableClassDescriptor supertypeOwner, @NotNull Map supertypes, Set allowedFinalSupertypes) { + Set typeConstructors = Sets.newHashSet(); + boolean classAppeared = false; + for (Map.Entry 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.getErrorHandler().genericError(typeReference.getNode(), "Only one class may appear in a supertype list"); + } + else { + classAppeared = true; + } + } + } + else { + trace.getErrorHandler().genericError(typeReference.getNode(), "Only classes and traits may serve as supertypes"); + } + + TypeConstructor constructor = supertype.getConstructor(); + if (!typeConstructors.add(constructor)) { + trace.getErrorHandler().genericError(typeReference.getNode(), "A supertype appears twice"); + } + + if (constructor.isSealed() && !allowedFinalSupertypes.contains(constructor)) { + trace.getErrorHandler().genericError(typeReference.getNode(), "This type is final, so it cannot be inherited from"); + } + } + } + + private void resolveClassAnnotations() { + + } + + private void resolveAnonymousInitializers() { + for (Map.Entry entry : typeHierarchyResolver.getClasses().entrySet()) { + resolveAnonymousInitializers(entry.getKey(), entry.getValue()); + } + for (Map.Entry entry : typeHierarchyResolver.getObjects().entrySet()) { + resolveAnonymousInitializers(entry.getKey(), entry.getValue()); + } + } + + private void resolveAnonymousInitializers(JetClassOrObject jetClassOrObject, MutableClassDescriptor classDescriptor) { + List anonymousInitializers = jetClassOrObject.getAnonymousInitializers(); + if (jetClassOrObject.hasPrimaryConstructor()) { + ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); + assert primaryConstructor != null; + final JetScope scopeForConstructor = getInnerScopeForConstructor(primaryConstructor, classDescriptor.getScopeForMemberResolution(), true); + JetTypeInferrer.Services typeInferrer = semanticServices.getTypeInferrerServices(createFieldAssignTrackingTrace(), JetFlowInformationProvider.NONE); // TODO : flow + for (JetClassInitializer anonymousInitializer : anonymousInitializers) { + typeInferrer.getType(scopeForConstructor, anonymousInitializer.getBody(), NO_EXPECTED_TYPE); + } + } + else { + for (JetClassInitializer anonymousInitializer : anonymousInitializers) { + trace.getErrorHandler().genericError(anonymousInitializer.getNode(), "Anonymous initializers are only allowed in the presence of a primary constructor"); + } + } + } + + private void resolveSecondaryConstructorBodies() { + for (Map.Entry entry : declarationResolver.getConstructors().entrySet()) { + JetDeclaration declaration = entry.getKey(); + ConstructorDescriptor descriptor = entry.getValue(); + + resolveSecondaryConstructorBody((JetConstructor) declaration, descriptor, ((MutableClassDescriptor) descriptor.getContainingDeclaration()).getScopeForMemberResolution()); + + assert descriptor.getReturnType() != null; + } + } + + private void resolveSecondaryConstructorBody(JetConstructor declaration, final ConstructorDescriptor descriptor, final JetScope declaringScope) { + final JetScope functionInnerScope = getInnerScopeForConstructor(descriptor, declaringScope, false); + + final JetTypeInferrer.Services typeInferrerForInitializers = semanticServices.getTypeInferrerServices(traceForConstructors, JetFlowInformationProvider.NONE); + + JetClass containingClass = PsiTreeUtil.getParentOfType(declaration, JetClass.class); + assert containingClass != null : "This must be guaranteed by the parser"; + if (!containingClass.hasPrimaryConstructor()) { + trace.getErrorHandler().genericError(declaration.getNameNode(), "A secondary constructor may appear only in a class that has a primary constructor"); + } + else { + List initializers = declaration.getInitializers(); + if (initializers.isEmpty()) { + trace.getErrorHandler().genericError(declaration.getNameNode(), "Secondary constructors must have an initializer list"); + } + else { + initializers.get(0).accept(new JetVisitorVoid() { + @Override + public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) { + JetTypeReference typeReference = call.getTypeReference(); + if (typeReference != null) { + typeInferrerForInitializers.getCallResolver().resolveCall(trace, functionInnerScope, null, call, NO_EXPECTED_TYPE); + } + } + + @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(); + + typeInferrerForInitializers.getCallResolver().resolveCall(trace, + functionInnerScope, + null, call, NO_EXPECTED_TYPE); +// call.getThisReference(), +// classDescriptor, +// classDescriptor.getDefaultType(), +// call); +// trace.getErrorHandler().genericError(call.getNode(), "this-calls are not supported"); + } + + @Override + public void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier) { + trace.getErrorHandler().genericError(specifier.getNode(), "'by'-clause is only supported for primary constructors"); + } + + @Override + public void visitDelegationToSuperClassSpecifier(JetDelegatorToSuperClass specifier) { + trace.getErrorHandler().genericError(specifier.getNode(), "Constructor parameters required"); + } + + @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.getErrorHandler().genericError(initializer.getNode(), "Only one call to 'this(...)' is allowed"); + } + } + } + JetExpression bodyExpression = declaration.getBodyExpression(); + if (bodyExpression != null) { + classDescriptorResolver.computeFlowData(declaration, bodyExpression); + JetFlowInformationProvider flowInformationProvider = classDescriptorResolver.computeFlowData(declaration, bodyExpression); + JetTypeInferrer.Services typeInferrer = semanticServices.getTypeInferrerServices(traceForConstructors, flowInformationProvider); + + typeInferrer.checkFunctionReturnType(functionInnerScope, declaration, JetStandardClasses.getUnitType()); + } + } + + @NotNull + private JetScope getInnerScopeForConstructor(@NotNull ConstructorDescriptor descriptor, @NotNull JetScope declaringScope, boolean primary) { + WritableScope constructorScope = new WritableScopeImpl(declaringScope, declaringScope.getContainingDeclaration(), trace.getErrorHandler()).setDebugName("Inner scope for constructor"); + for (PropertyDescriptor propertyDescriptor : ((MutableClassDescriptor) descriptor.getContainingDeclaration()).getProperties()) { + constructorScope.addPropertyDescriptorByFieldName("$" + propertyDescriptor.getName(), propertyDescriptor); + } + + constructorScope.setThisType(descriptor.getContainingDeclaration().getDefaultType()); + + for (ValueParameterDescriptor valueParameterDescriptor : descriptor.getValueParameters()) { + JetParameter parameter = (JetParameter) trace.getBindingContext().get(BindingContext.DESCRIPTOR_TO_DECLARATION, valueParameterDescriptor); + if (parameter.getValOrVarNode() == null || !primary) { + constructorScope.addVariableDescriptor(valueParameterDescriptor); + } + } + + constructorScope.addLabeledDeclaration(descriptor); // TODO : Labels for constructors?! + + return constructorScope; + } + + private void resolvePropertyDeclarationBodies() { + + // Member properties + Set processed = Sets.newHashSet(); + for (Map.Entry entry : typeHierarchyResolver.getClasses().entrySet()) { + JetClass jetClass = entry.getKey(); + MutableClassDescriptor classDescriptor = entry.getValue(); + + for (JetProperty property : jetClass.getProperties()) { + final PropertyDescriptor propertyDescriptor = declarationResolver.getProperties().get(property); + assert propertyDescriptor != null; + + JetScope declaringScope = declarationResolver.getDeclaringScopes().get(property); + + JetExpression initializer = property.getInitializer(); + if (initializer != null) { + ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); + if (primaryConstructor == null) { + trace.getErrorHandler().genericError(initializer.getNode(), "Property initializers are not allowed when no primary constructor is present"); + } + else { + JetScope scope = getInnerScopeForConstructor(primaryConstructor, classDescriptor.getScopeForMemberResolution(), true); + resolvePropertyInitializer(property, propertyDescriptor, initializer, scope); + } + } + + resolvePropertyAccessors(property, propertyDescriptor, declaringScope); + checkProperty(property, propertyDescriptor, classDescriptor); + processed.add(property); + } + } + + // Top-level properties & properties of objects + for (Map.Entry entry : declarationResolver.getProperties().entrySet()) { + JetProperty property = entry.getKey(); + if (processed.contains(property)) continue; + + final PropertyDescriptor propertyDescriptor = entry.getValue(); + JetScope declaringScope = declarationResolver.getDeclaringScopes().get(property); + + JetExpression initializer = property.getInitializer(); + if (initializer != null) { + resolvePropertyInitializer(property, propertyDescriptor, initializer, declaringScope); + } + + resolvePropertyAccessors(property, propertyDescriptor, declaringScope); + checkProperty(property, propertyDescriptor, null); + } + } + + private JetScope getPropertyDeclarationInnerScope(@NotNull JetScope outerScope, @NotNull PropertyDescriptor propertyDescriptor) { + WritableScopeImpl result = new WritableScopeImpl(outerScope, propertyDescriptor, trace.getErrorHandler()).setDebugName("Property declaration inner scope"); + for (TypeParameterDescriptor typeParameterDescriptor : propertyDescriptor.getTypeParameters()) { + result.addTypeParameterDescriptor(typeParameterDescriptor); + } + JetType receiverType = propertyDescriptor.getReceiverType(); + if (receiverType != null) { + result.setThisType(receiverType); + } + return result; + } + + private void resolvePropertyAccessors(JetProperty property, PropertyDescriptor propertyDescriptor, JetScope declaringScope) { + BindingTraceAdapter fieldAccessTrackingTrace = createFieldTrackingTrace(propertyDescriptor); + + WritableScope accessorScope = new WritableScopeImpl(getPropertyDeclarationInnerScope(declaringScope, propertyDescriptor), declaringScope.getContainingDeclaration(), trace.getErrorHandler()).setDebugName("Accessor scope"); + accessorScope.addPropertyDescriptorByFieldName("$" + propertyDescriptor.getName(), propertyDescriptor); + + JetPropertyAccessor getter = property.getGetter(); + PropertyGetterDescriptor getterDescriptor = propertyDescriptor.getGetter(); + if (getter != null && getterDescriptor != null) { + resolveFunctionBody(fieldAccessTrackingTrace, getter, getterDescriptor, accessorScope); + } + + JetPropertyAccessor setter = property.getSetter(); + PropertySetterDescriptor setterDescriptor = propertyDescriptor.getSetter(); + if (setter != null && setterDescriptor != null) { + resolveFunctionBody(fieldAccessTrackingTrace, setter, setterDescriptor, accessorScope); + } + } + + protected void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor, @Nullable ClassDescriptor classDescriptor) { + JetExpression initializer = property.getInitializer(); + JetPropertyAccessor getter = property.getGetter(); + JetPropertyAccessor setter = property.getSetter(); + PsiElement nameIdentifier = property.getNameIdentifier(); + ASTNode nameNode = nameIdentifier == null ? property.getNode() : nameIdentifier.getNode(); + if (propertyDescriptor.getModality() == Modality.ABSTRACT) { + if (classDescriptor == null) { + trace.getErrorHandler().genericError(property.getModifierList().getModifierNode(JetTokens.ABSTRACT_KEYWORD), + "Global property can not be abstract"); + return; + } + if (classDescriptor.getModality() != Modality.ABSTRACT) { + trace.getErrorHandler().genericError(property.getModifierList().getModifierNode(JetTokens.ABSTRACT_KEYWORD), + "Abstract property " + property.getName() + " in non-abstract class " + classDescriptor.getName()); + return; + } + if (initializer != null) { + trace.getErrorHandler().genericError(initializer.getNode(), "Property with initializer can not be abstract"); + } + if (getter != null && getter.getBodyExpression() != null) { + trace.getErrorHandler().genericError(getter.getNode(), "Property with getter implementation can not be abstract"); + } + if (setter != null && setter.getBodyExpression() != null) { + trace.getErrorHandler().genericError(setter.getNode(), "Property with setter implementation can not be abstract"); + } + return; + } + boolean backingFieldRequired = trace.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor); + if (backingFieldRequired) { + if (initializer == null && !trace.getBindingContext().get(BindingContext.IS_INITIALIZED, propertyDescriptor)) { + if (classDescriptor == null || (getter != null && getter.getBodyExpression() != null) || (setter != null && setter.getBodyExpression() != null)) { + trace.getErrorHandler().genericError(nameNode, "Property must be initialized"); + } else if (classDescriptor.getKind() != ClassKind.TRAIT) { + trace.getErrorHandler().genericError(nameNode, "Property must be initialized or be abstract"); + } + } + } + else { + if (initializer != null) { + trace.getErrorHandler().genericError(initializer.getNode(), "Initializer is not allowed here because this property has no backing field"); + } + } + } + + private BindingTraceAdapter createFieldTrackingTrace(final PropertyDescriptor propertyDescriptor) { + return new BindingTraceAdapter(traceForMembers).addHandler(BindingContext.REFERENCE_TARGET, new BindingTraceAdapter.RecordHandler() { + @Override + public void handleRecord(WritableSlice slice, JetReferenceExpression expression, DeclarationDescriptor descriptor) { + if (expression instanceof JetSimpleNameExpression) { + JetSimpleNameExpression simpleNameExpression = (JetSimpleNameExpression) expression; + if (simpleNameExpression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) { + // This check may be considered redundant as long as $x is only accessible from accessors to $x + if (descriptor == propertyDescriptor) { // TODO : original? + traceForMembers.record(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor); // TODO: this trace? + } + } + } + } + }); + } + + private BindingTraceAdapter createFieldAssignTrackingTrace() { + return new BindingTraceAdapter(traceForConstructors).addHandler(BindingContext.VARIABLE_ASSIGNMENT, new BindingTraceAdapter.RecordHandler() { + @Override + public void handleRecord(WritableSlice jetExpressionBooleanWritableSlice, JetExpression expression, DeclarationDescriptor descriptor) { + if (expression instanceof JetSimpleNameExpression) { + JetSimpleNameExpression variable = (JetSimpleNameExpression) expression; + if (variable.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) { + if (descriptor instanceof PropertyDescriptor) { + traceForMembers.record(BindingContext.IS_INITIALIZED, (PropertyDescriptor) descriptor); + } + } + } + } + }); + } + + private void resolvePropertyInitializer(JetProperty property, PropertyDescriptor propertyDescriptor, JetExpression initializer, JetScope scope) { + JetFlowInformationProvider flowInformationProvider = classDescriptorResolver.computeFlowData(property, initializer); // TODO : flow JET-15 + JetTypeInferrer.Services typeInferrer = semanticServices.getTypeInferrerServices(traceForConstructors, flowInformationProvider); + JetType type = typeInferrer.getType(getPropertyDeclarationInnerScope(scope, propertyDescriptor), initializer, NO_EXPECTED_TYPE); + + JetType expectedType = propertyDescriptor.getInType(); + if (expectedType == null) { + expectedType = propertyDescriptor.getOutType(); + } + if (type != null && expectedType != null + && !semanticServices.getTypeChecker().isSubtypeOf(type, expectedType)) { + trace.getErrorHandler().typeMismatch(initializer, expectedType, type); + } + } + + private void resolveFunctionBodies() { + for (Map.Entry entry : declarationResolver.getFunctions().entrySet()) { + JetDeclaration declaration = entry.getKey(); + FunctionDescriptor descriptor = entry.getValue(); + + JetScope declaringScope = declarationResolver.getDeclaringScopes().get(declaration); + assert declaringScope != null; + + resolveFunctionBody(traceForMembers, (JetNamedFunction) declaration, descriptor, declaringScope); + + assert descriptor.getReturnType() != null; + } + } + + private void resolveFunctionBody( + @NotNull BindingTrace trace, + @NotNull JetDeclarationWithBody function, + @NotNull FunctionDescriptor functionDescriptor, + @NotNull JetScope declaringScope) { + JetExpression bodyExpression = function.getBodyExpression(); + + if (bodyExpression != null) { + JetFlowInformationProvider flowInformationProvider = classDescriptorResolver.computeFlowData(function.asElement(), bodyExpression); + JetTypeInferrer.Services typeInferrer = semanticServices.getTypeInferrerServices(trace, flowInformationProvider); + + typeInferrer.checkFunctionReturnType(declaringScope, function, functionDescriptor); + } + + checkFunction(function, functionDescriptor); + assert functionDescriptor.getReturnType() != null; + } + + protected void checkFunction(JetDeclarationWithBody function, FunctionDescriptor functionDescriptor) { + DeclarationDescriptor containingDescriptor = functionDescriptor.getContainingDeclaration(); + PsiElement nameIdentifier; + JetModifierList modifierList; + if (function instanceof JetNamedFunction) { + JetNamedFunction namedFunction = (JetNamedFunction) function; + nameIdentifier = namedFunction.getNameIdentifier(); + modifierList = namedFunction.getModifierList(); + } + else if (function instanceof JetPropertyAccessor) { + return; +// JetPropertyAccessor propertyAccessor = (JetPropertyAccessor) function; +// nameIdentifier = propertyAccessor.getNamePlaceholder(); +// modifierList = propertyAccessor.getModifierList(); + } + else { + throw new UnsupportedOperationException(); + } + ASTNode abstractNode = modifierList != null ? modifierList.getModifierNode(JetTokens.ABSTRACT_KEYWORD) : null; + boolean hasAbstractModifier = abstractNode != null; + if (containingDescriptor instanceof ClassDescriptor) { + ClassDescriptor classDescriptor = (ClassDescriptor) containingDescriptor; + boolean inTrait = classDescriptor.getKind() == ClassKind.TRAIT; + boolean inEnum = classDescriptor.getKind() == ClassKind.ENUM_CLASS; + boolean inAbstractClass = classDescriptor.getModality() == Modality.ABSTRACT; + if (hasAbstractModifier && !inAbstractClass && !inTrait && !inEnum) { + trace.getErrorHandler().genericError(abstractNode, "Abstract method " + function.getName() + " in non-abstract class " + classDescriptor.getName()); + } + if (hasAbstractModifier && inTrait) { + trace.getErrorHandler().genericWarning(abstractNode, "Abstract modifier is not necessary in traits"); + } + if (function.getBodyExpression() != null && hasAbstractModifier) { + trace.getErrorHandler().genericError(abstractNode, "Method " + function.getName() + " with body can not be abstract"); + } + if (function.getBodyExpression() == null && !hasAbstractModifier && !inTrait && nameIdentifier != null) { + trace.getErrorHandler().genericError(nameIdentifier.getNode(), "Method " + function.getName() + " without body must be abstract"); + } + return; + } + if (hasAbstractModifier) { + trace.getErrorHandler().genericError(abstractNode, "Function " + function.getName() + " can not be abstract"); + } + if (function.getBodyExpression() == null && !hasAbstractModifier && nameIdentifier != null) { + trace.getErrorHandler().genericError(nameIdentifier.getNode(), "Function " + function.getName() + " must have body"); + } + } + +} diff --git a/idea/src/org/jetbrains/jet/lang/resolve/DeclarationResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/DeclarationResolver.java new file mode 100644 index 0000000000000000000000000000000000000000..fab41731b979c2df7f1f972cd23ee93878b2ff5f --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/resolve/DeclarationResolver.java @@ -0,0 +1,197 @@ +package org.jetbrains.jet.lang.resolve; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.JetSemanticServices; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.psi.*; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.jetbrains.jet.lang.resolve.BindingContext.ANNOTATION; + +/** +* @author abreslav +*/ +public class DeclarationResolver { + private final BindingTrace trace; + private final AnnotationResolver annotationResolver; + private final TypeHierarchyResolver typeHierarchyResolver; + private final ClassDescriptorResolver classDescriptorResolver; + + private final Map functions = Maps.newLinkedHashMap(); + private final Map constructors = Maps.newLinkedHashMap(); + private final Map properties = Maps.newLinkedHashMap(); + private final Set primaryConstructorParameterProperties = Sets.newHashSet(); + private final Map declaringScopes = Maps.newHashMap(); + + public DeclarationResolver(JetSemanticServices semanticServices, BindingTrace trace, TypeHierarchyResolver typeHierarchyResolver) { + this.trace = trace; + this.typeHierarchyResolver = typeHierarchyResolver; + this.annotationResolver = new AnnotationResolver(semanticServices, trace); + this.classDescriptorResolver = semanticServices.getClassDescriptorResolver(trace); + } + + public void process() { + resolveConstructorHeaders(); + resolveAnnotationStubsOnClassesAndConstructors(); + resolveFunctionAndPropertyHeaders(); + } + + private void resolveConstructorHeaders() { + for (Map.Entry entry : typeHierarchyResolver.getClasses().entrySet()) { + JetClass jetClass = entry.getKey(); + MutableClassDescriptor classDescriptor = entry.getValue(); + + processPrimaryConstructor(classDescriptor, jetClass); + for (JetConstructor jetConstructor : jetClass.getSecondaryConstructors()) { + processSecondaryConstructor(classDescriptor, jetConstructor); + } + } + } + + private void resolveAnnotationStubsOnClassesAndConstructors() { + for (Map.Entry entry : typeHierarchyResolver.getClasses().entrySet()) { + JetClass jetClass = entry.getKey(); + MutableClassDescriptor mutableClassDescriptor = entry.getValue(); + + JetModifierList modifierList = jetClass.getModifierList(); + if (modifierList != null) { + List annotationEntries = modifierList.getAnnotationEntries(); + for (JetAnnotationEntry annotationEntry : annotationEntries) { + AnnotationDescriptor annotationDescriptor = trace.get(ANNOTATION, annotationEntry); + if (annotationDescriptor != null) { + annotationResolver.resolveAnnotationStub(mutableClassDescriptor.getScopeForSupertypeResolution(), annotationEntry, annotationDescriptor); + } + } + } + } + } + + private void resolveFunctionAndPropertyHeaders() { + for (Map.Entry entry : typeHierarchyResolver.getNamespaceScopes().entrySet()) { + JetNamespace namespace = entry.getKey(); + WritableScope namespaceScope = entry.getValue(); + NamespaceLike namespaceDescriptor = typeHierarchyResolver.getNamespaceDescriptors().get(namespace); + + resolveFunctionAndPropertyHeaders(namespace.getDeclarations(), namespaceScope, namespaceDescriptor); + } + for (Map.Entry entry : typeHierarchyResolver.getClasses().entrySet()) { + JetClass jetClass = entry.getKey(); + MutableClassDescriptor classDescriptor = entry.getValue(); + + resolveFunctionAndPropertyHeaders(jetClass.getDeclarations(), classDescriptor.getScopeForMemberResolution(), classDescriptor); +// processPrimaryConstructor(classDescriptor, jetClass); +// for (JetConstructor jetConstructor : jetClass.getSecondaryConstructors()) { +// processSecondaryConstructor(classDescriptor, jetConstructor); +// } + } + for (Map.Entry entry : typeHierarchyResolver.getObjects().entrySet()) { + JetObjectDeclaration object = entry.getKey(); + MutableClassDescriptor classDescriptor = entry.getValue(); + + resolveFunctionAndPropertyHeaders(object.getDeclarations(), classDescriptor.getScopeForMemberResolution(), classDescriptor); + } + + // TODO : Extensions + } + + private void resolveFunctionAndPropertyHeaders(@NotNull List declarations, final @NotNull JetScope scope, final @NotNull NamespaceLike namespaceLike) { + for (JetDeclaration declaration : declarations) { + declaration.accept(new JetVisitorVoid() { + @Override + public void visitNamedFunction(JetNamedFunction function) { + FunctionDescriptorImpl functionDescriptor = classDescriptorResolver.resolveFunctionDescriptor(namespaceLike, scope, function); + namespaceLike.addFunctionDescriptor(functionDescriptor); + functions.put(function, functionDescriptor); + declaringScopes.put(function, scope); + } + + @Override + public void visitProperty(JetProperty property) { + PropertyDescriptor propertyDescriptor = classDescriptorResolver.resolvePropertyDescriptor(namespaceLike, scope, property); + namespaceLike.addPropertyDescriptor(propertyDescriptor); + properties.put(property, propertyDescriptor); + declaringScopes.put(property, scope); + } + + @Override + public void visitObjectDeclaration(JetObjectDeclaration declaration) { + PropertyDescriptor propertyDescriptor = classDescriptorResolver.resolveObjectDeclarationAsPropertyDescriptor(namespaceLike, declaration, typeHierarchyResolver.getObjects().get(declaration)); + namespaceLike.addPropertyDescriptor(propertyDescriptor); + } + + @Override + public void visitEnumEntry(JetEnumEntry enumEntry) { + if (enumEntry.getPrimaryConstructorParameterList() == null) { + PropertyDescriptor propertyDescriptor = classDescriptorResolver.resolveObjectDeclarationAsPropertyDescriptor(namespaceLike, enumEntry, typeHierarchyResolver.getClasses().get(enumEntry)); + MutableClassDescriptor classObjectDescriptor = ((MutableClassDescriptor) namespaceLike).getClassObjectDescriptor(); + assert classObjectDescriptor != null; + classObjectDescriptor.addPropertyDescriptor(propertyDescriptor); + } + } + }); + } + } + + private void processPrimaryConstructor(MutableClassDescriptor classDescriptor, JetClass klass) { + if (!klass.hasPrimaryConstructor()) return; + + if (classDescriptor.getKind() == ClassKind.TRAIT) { + trace.getErrorHandler().genericError(klass.getPrimaryConstructorParameterList().getNode(), "A trait may not have a constructor"); + } + + // TODO : not all the parameters are real properties + JetScope memberScope = classDescriptor.getScopeForSupertypeResolution(); + ConstructorDescriptor constructorDescriptor = classDescriptorResolver.resolvePrimaryConstructorDescriptor(memberScope, classDescriptor, klass); + for (JetParameter parameter : klass.getPrimaryConstructorParameters()) { + PropertyDescriptor propertyDescriptor = classDescriptorResolver.resolvePrimaryConstructorParameterToAProperty( + classDescriptor, + memberScope, + parameter + ); + classDescriptor.addPropertyDescriptor(propertyDescriptor); + primaryConstructorParameterProperties.add(propertyDescriptor); + } + if (constructorDescriptor != null) { + classDescriptor.setPrimaryConstructor(constructorDescriptor); + } + } + + private void processSecondaryConstructor(MutableClassDescriptor classDescriptor, JetConstructor constructor) { + if (classDescriptor.getKind() == ClassKind.TRAIT) { + trace.getErrorHandler().genericError(constructor.getNameNode(), "A trait may not have a constructor"); + } + ConstructorDescriptor constructorDescriptor = classDescriptorResolver.resolveSecondaryConstructorDescriptor( + classDescriptor.getScopeForMemberResolution(), + classDescriptor, + constructor); + classDescriptor.addConstructor(constructorDescriptor); + constructors.put(constructor, constructorDescriptor); + declaringScopes.put(constructor, classDescriptor.getScopeForMemberLookup()); + } + + public Set getPrimaryConstructorParameterProperties() { + return primaryConstructorParameterProperties; + } + + public Map getConstructors() { + return constructors; + } + + public Map getProperties() { + return properties; + } + + public Map getDeclaringScopes() { + return declaringScopes; + } + + public Map getFunctions() { + return functions; + } +} diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index 47a45e24fde9a0acf6897b39cbc8c693e43b2bf5..d03f0a826e0d836cc5b059c375edbff97c559953 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -1,83 +1,24 @@ package org.jetbrains.jet.lang.resolve; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import com.intellij.lang.ASTNode; -import com.intellij.psi.PsiElement; -import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.JetSemanticServices; -import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; import org.jetbrains.jet.lang.descriptors.*; -import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.psi.*; -import org.jetbrains.jet.lang.types.*; -import org.jetbrains.jet.lexer.JetTokens; -import org.jetbrains.jet.util.slicedmap.WritableSlice; -import java.util.*; - -import static org.jetbrains.jet.lang.resolve.BindingContext.ANNOTATION; -import static org.jetbrains.jet.lang.types.JetTypeInferrer.NO_EXPECTED_TYPE; +import java.util.Collections; +import java.util.List; /** * @author abreslav */ public class TopDownAnalyzer { - - private final Map classes = Maps.newLinkedHashMap(); - private final Map objects = Maps.newLinkedHashMap(); - protected final Map namespaceScopes = Maps.newHashMap(); - protected final Map namespaceDescriptors = Maps.newHashMap(); - - private final Map functions = Maps.newLinkedHashMap(); - private final Map constructors = Maps.newLinkedHashMap(); - private final Map properties = Maps.newLinkedHashMap(); - private final Map declaringScopes = Maps.newHashMap(); - private final Set primaryConstructorParameterProperties = Sets.newHashSet(); - private final JetSemanticServices semanticServices; - private final ClassDescriptorResolver classDescriptorResolver; private final BindingTrace trace; - private final BindingTraceAdapter traceForConstructors; - private final BindingTraceAdapter traceForMembers; - private final AnnotationResolver annotationResolver; public TopDownAnalyzer(JetSemanticServices semanticServices, @NotNull BindingTrace bindingTrace) { this.semanticServices = semanticServices; - this.classDescriptorResolver = semanticServices.getClassDescriptorResolver(bindingTrace); this.trace = bindingTrace; - - // This allows access to backing fields - this.traceForConstructors = new BindingTraceAdapter(bindingTrace).addHandler(BindingContext.REFERENCE_TARGET, new BindingTraceAdapter.RecordHandler() { - @Override - public void handleRecord(WritableSlice slice, JetReferenceExpression expression, DeclarationDescriptor descriptor) { - if (expression instanceof JetSimpleNameExpression) { - JetSimpleNameExpression simpleNameExpression = (JetSimpleNameExpression) expression; - if (simpleNameExpression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) { - if (!trace.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) descriptor)) { - TopDownAnalyzer.this.trace.getErrorHandler().genericError(expression.getNode(), "This property does not have a backing field"); - } - } - } - } - }); - - // This tracks access to properties in order to register primary constructor parameters that yield real fields (JET-9) - this.traceForMembers = new BindingTraceAdapter(bindingTrace).addHandler(BindingContext.REFERENCE_TARGET, new BindingTraceAdapter.RecordHandler() { - @Override - public void handleRecord(WritableSlice slice, JetReferenceExpression expression, DeclarationDescriptor descriptor) { - if (descriptor instanceof PropertyDescriptor) { - PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; - if (primaryConstructorParameterProperties.contains(propertyDescriptor)) { - traceForMembers.record(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor); - } - } - } - }); - - this.annotationResolver = new AnnotationResolver(semanticServices, trace); } public void processObject(@NotNull JetScope outerScope, @NotNull DeclarationDescriptor containingDeclaration, @NotNull JetObjectDeclaration object) { @@ -116,1032 +57,36 @@ public class TopDownAnalyzer { } public void process(@NotNull JetScope outerScope, NamespaceLike owner, @NotNull List declarations) { - collectNamespacesAndClassifiers(outerScope, owner, declarations); // namespaceScopes, classes - - createTypeConstructors(); // create type constructors for classes and generic parameters - resolveTypesInClassHeaders(); // Generic bounds and types in supertype lists (no expressions or constructor resolution) - checkTypesInClassHeaders(); // Generic bounds and supertype lists - - resolveConstructorHeaders(); - - resolveAnnotationStubsOnClassesAndConstructors(); - - resolveFunctionAndPropertyHeaders(); - - resolveBehaviorDeclarationBodies(); - } - - private void collectNamespacesAndClassifiers( - @NotNull final JetScope outerScope, - @NotNull final NamespaceLike owner, - @NotNull Collection declarations) { - for (JetDeclaration declaration : declarations) { - declaration.accept(new JetVisitorVoid() { - @Override - public void visitNamespace(JetNamespace namespace) { - - String name = namespace.getName(); - if (name == null) { - name = ""; - } - NamespaceDescriptorImpl namespaceDescriptor = owner.getNamespace(name); - if (namespaceDescriptor == null) { - namespaceDescriptor = new NamespaceDescriptorImpl( - owner.getOriginal(), - Collections.emptyList(), // TODO - name - ); - namespaceDescriptor.initialize(new WritableScopeImpl(JetScope.EMPTY, namespaceDescriptor, trace.getErrorHandler()).setDebugName("Namespace member scope")); - owner.addNamespace(namespaceDescriptor); - trace.record(BindingContext.NAMESPACE, namespace, namespaceDescriptor); - } - namespaceDescriptors.put(namespace, namespaceDescriptor); - - WriteThroughScope namespaceScope = new WriteThroughScope(outerScope, namespaceDescriptor.getMemberScope(), trace.getErrorHandler()); - namespaceScopes.put(namespace, namespaceScope); - - processImports(namespace, namespaceScope, outerScope); - - collectNamespacesAndClassifiers(namespaceScope, namespaceDescriptor, namespace.getDeclarations()); - } - - @Override - public void visitClass(JetClass klass) { - MutableClassDescriptor mutableClassDescriptor = new MutableClassDescriptor(trace, owner, outerScope, getClassKind(klass)); - - if (klass.hasModifier(JetTokens.ENUM_KEYWORD)) { - MutableClassDescriptor classObjectDescriptor = new MutableClassDescriptor(trace, mutableClassDescriptor, outerScope, ClassKind.OBJECT); - classObjectDescriptor.setName("class-object-for-" + klass.getName()); - classObjectDescriptor.setModality(Modality.FINAL); - classObjectDescriptor.createTypeConstructor(); - createPrimaryConstructor(classObjectDescriptor); - mutableClassDescriptor.setClassObjectDescriptor(classObjectDescriptor); - } - visitClassOrObject( - klass, - (Map) classes, - owner, - outerScope, - mutableClassDescriptor); - owner.addClassifierDescriptor(mutableClassDescriptor); - } - - @Override - public void visitObjectDeclaration(JetObjectDeclaration declaration) { - createClassDescriptorForObject(declaration, owner); - } - - @Override - public void visitEnumEntry(JetEnumEntry enumEntry) { - MutableClassDescriptor classObjectDescriptor = ((MutableClassDescriptor) owner).getClassObjectDescriptor(); - assert classObjectDescriptor != null : enumEntry.getParent().getText(); - if (enumEntry.getPrimaryConstructorParameterList() == null) { - MutableClassDescriptor classDescriptor = createClassDescriptorForObject(enumEntry, classObjectDescriptor); - objects.remove(enumEntry); - classes.put(enumEntry, classDescriptor); - } - else { - MutableClassDescriptor mutableClassDescriptor = new MutableClassDescriptor(trace, classObjectDescriptor, outerScope, ClassKind.CLASS); // TODO : Special kind for enum entry classes? - visitClassOrObject( - enumEntry, - (Map) classes, - classObjectDescriptor, - outerScope, - mutableClassDescriptor); - classObjectDescriptor.addClassifierDescriptor(mutableClassDescriptor); - } - } - - private MutableClassDescriptor createClassDescriptorForObject(@NotNull JetClassOrObject declaration, @NotNull NamespaceLike owner) { - MutableClassDescriptor mutableClassDescriptor = new MutableClassDescriptor(trace, owner, outerScope, ClassKind.OBJECT) { - @Override - public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) { - return ClassObjectStatus.NOT_ALLOWED; - } - }; - visitClassOrObject(declaration, (Map) objects, owner, outerScope, mutableClassDescriptor); - createPrimaryConstructor(mutableClassDescriptor); - trace.record(BindingContext.CLASS, declaration, mutableClassDescriptor); - return mutableClassDescriptor; - } - - private void createPrimaryConstructor(MutableClassDescriptor mutableClassDescriptor) { - ConstructorDescriptorImpl constructorDescriptor = new ConstructorDescriptorImpl(mutableClassDescriptor, Collections.emptyList(), true); - constructorDescriptor.initialize(Collections.emptyList(), Collections.emptyList(), - Modality.FINAL); - // TODO : make the constructor private? - mutableClassDescriptor.setPrimaryConstructor(constructorDescriptor); - } - - private void visitClassOrObject(@NotNull JetClassOrObject declaration, Map map, NamespaceLike owner, JetScope outerScope, MutableClassDescriptor mutableClassDescriptor) { - mutableClassDescriptor.setName(JetPsiUtil.safeName(declaration.getName())); - - map.put(declaration, mutableClassDescriptor); - declaringScopes.put((JetDeclaration) declaration, outerScope); - - JetScope classScope = mutableClassDescriptor.getScopeForMemberResolution(); - collectNamespacesAndClassifiers(classScope, mutableClassDescriptor, declaration.getDeclarations()); - } - - @Override - public void visitTypedef(JetTypedef typedef) { - trace.getErrorHandler().genericError(typedef.getNode(), "Unsupported [TopDownAnalyzer]"); - } - - @Override - public void visitClassObject(JetClassObject classObject) { - JetObjectDeclaration objectDeclaration = classObject.getObjectDeclaration(); - if (objectDeclaration != null) { - NamespaceLike.ClassObjectStatus status = owner.setClassObjectDescriptor(createClassDescriptorForObject(objectDeclaration, owner)); - switch (status) { - case DUPLICATE: - trace.getErrorHandler().genericError(classObject.getNode(), "Only one class object is allowed per class"); - break; - case NOT_ALLOWED: - trace.getErrorHandler().genericError(classObject.getNode(), "A class object is not allowed here"); - break; - } - } - } - }); - } - } - - @NotNull - private ClassKind getClassKind(@NotNull JetClass jetClass) { - if (jetClass.isTrait()) return ClassKind.TRAIT; - if (jetClass.hasModifier(JetTokens.ANNOTATION_KEYWORD)) return ClassKind.ANNOTATION_CLASS; - if (jetClass.hasModifier(JetTokens.ENUM_KEYWORD)) return ClassKind.ENUM_CLASS; - return ClassKind.CLASS; - } - - private void processImports(@NotNull JetNamespace namespace, @NotNull WriteThroughScope namespaceScope, @NotNull JetScope outerScope) { - List importDirectives = namespace.getImportDirectives(); - for (JetImportDirective importDirective : importDirectives) { - if (importDirective.isAbsoluteInRootNamespace()) { - trace.getErrorHandler().genericError(namespace.getNode(), "Unsupported by TDA"); // TODO - continue; - } - if (importDirective.isAllUnder()) { - JetExpression importedReference = importDirective.getImportedReference(); - if (importedReference != null) { - JetTypeInferrer.Services typeInferrerServices = semanticServices.getTypeInferrerServices(trace, JetFlowInformationProvider.THROW_EXCEPTION); - JetType type = typeInferrerServices.getTypeWithNamespaces(namespaceScope, importedReference); - if (type != null) { - namespaceScope.importScope(type.getMemberScope()); - } - } - } - else { - ClassifierDescriptor classifierDescriptor = null; - JetSimpleNameExpression referenceExpression = null; + TypeHierarchyResolver typeHierarchyResolver = new TypeHierarchyResolver(semanticServices, trace); + typeHierarchyResolver.process(outerScope, owner, declarations); - JetExpression importedReference = importDirective.getImportedReference(); - if (importedReference instanceof JetDotQualifiedExpression) { - JetDotQualifiedExpression reference = (JetDotQualifiedExpression) importedReference; - JetType type = semanticServices.getTypeInferrerServices(trace, JetFlowInformationProvider.THROW_EXCEPTION).getTypeWithNamespaces(namespaceScope, reference.getReceiverExpression()); - JetExpression selectorExpression = reference.getSelectorExpression(); - if (selectorExpression != null) { - referenceExpression = (JetSimpleNameExpression) selectorExpression; - String referencedName = referenceExpression.getReferencedName(); - if (type != null && referencedName != null) { - classifierDescriptor = type.getMemberScope().getClassifier(referencedName); - } - } - } - else { - assert importedReference instanceof JetSimpleNameExpression; - referenceExpression = (JetSimpleNameExpression) importedReference; - - String referencedName = referenceExpression.getReferencedName(); - if (referencedName != null) { - classifierDescriptor = outerScope.getClassifier(referencedName); - } - } - - if (classifierDescriptor != null) { - trace.record(BindingContext.REFERENCE_TARGET, referenceExpression, classifierDescriptor); - - String aliasName = importDirective.getAliasName(); - String importedClassifierName = aliasName != null ? aliasName : classifierDescriptor.getName(); - namespaceScope.importClassifierAlias(importedClassifierName, classifierDescriptor); - } - } - } - } - - private void createTypeConstructors() { - for (Map.Entry entry : classes.entrySet()) { - JetClass jetClass = entry.getKey(); - MutableClassDescriptor descriptor = entry.getValue(); - classDescriptorResolver.resolveMutableClassDescriptor(jetClass, descriptor); - descriptor.createTypeConstructor(); - } - for (Map.Entry entry : objects.entrySet()) { - MutableClassDescriptor descriptor = entry.getValue(); - descriptor.setModality(Modality.FINAL); - descriptor.createTypeConstructor(); - } - } + DeclarationResolver declarationResolver = new DeclarationResolver(semanticServices, trace, typeHierarchyResolver); + declarationResolver.process(); - private void resolveTypesInClassHeaders() { - for (Map.Entry entry : classes.entrySet()) { - JetClass jetClass = entry.getKey(); - MutableClassDescriptor descriptor = entry.getValue(); - classDescriptorResolver.resolveGenericBounds(jetClass, descriptor.getScopeForSupertypeResolution(), descriptor.getTypeConstructor().getParameters()); - classDescriptorResolver.resolveSupertypes(jetClass, descriptor); - } - for (Map.Entry entry : objects.entrySet()) { - JetClassOrObject jetClass = entry.getKey(); - MutableClassDescriptor descriptor = entry.getValue(); - classDescriptorResolver.resolveSupertypes(jetClass, descriptor); - } + new BodyResolver(semanticServices, trace, typeHierarchyResolver, declarationResolver).resolveBehaviorDeclarationBodies(); } - private void checkTypesInClassHeaders() { - for (Map.Entry entry : classes.entrySet()) { - JetClass jetClass = entry.getKey(); - - for (JetDelegationSpecifier delegationSpecifier : jetClass.getDelegationSpecifiers()) { - JetTypeReference typeReference = delegationSpecifier.getTypeReference(); - if (typeReference != null) { - JetType type = trace.getBindingContext().get(BindingContext.TYPE, typeReference); - if (type != null) { - classDescriptorResolver.checkBounds(typeReference, type); - } - } - } - - for (JetTypeParameter jetTypeParameter : jetClass.getTypeParameters()) { - JetTypeReference extendsBound = jetTypeParameter.getExtendsBound(); - if (extendsBound != null) { - JetType type = trace.getBindingContext().get(BindingContext.TYPE, extendsBound); - if (type != null) { - classDescriptorResolver.checkBounds(extendsBound, type); - } - } - } - - for (JetTypeConstraint constraint : jetClass.getTypeConstaints()) { - JetTypeReference extendsBound = constraint.getBoundTypeReference(); - if (extendsBound != null) { - JetType type = trace.getBindingContext().get(BindingContext.TYPE, extendsBound); - if (type != null) { - classDescriptorResolver.checkBounds(extendsBound, type); - } - } - } - } - } - - private void resolveConstructorHeaders() { - for (Map.Entry entry : classes.entrySet()) { - JetClass jetClass = entry.getKey(); - MutableClassDescriptor classDescriptor = entry.getValue(); - - processPrimaryConstructor(classDescriptor, jetClass); - for (JetConstructor jetConstructor : jetClass.getSecondaryConstructors()) { - processSecondaryConstructor(classDescriptor, jetConstructor); - } - } - - } - - private void resolveAnnotationStubsOnClassesAndConstructors() { - for (Map.Entry entry : classes.entrySet()) { - JetClass jetClass = entry.getKey(); - MutableClassDescriptor mutableClassDescriptor = entry.getValue(); - - JetModifierList modifierList = jetClass.getModifierList(); - if (modifierList != null) { - List annotationEntries = modifierList.getAnnotationEntries(); - for (JetAnnotationEntry annotationEntry : annotationEntries) { - AnnotationDescriptor annotationDescriptor = trace.get(ANNOTATION, annotationEntry); - if (annotationDescriptor != null) { - annotationResolver.resolveAnnotationStub(mutableClassDescriptor.getScopeForSupertypeResolution(), annotationEntry, annotationDescriptor); - } - } - } - } - } - - private void resolveFunctionAndPropertyHeaders() { - for (Map.Entry entry : namespaceScopes.entrySet()) { - JetNamespace namespace = entry.getKey(); - WritableScope namespaceScope = entry.getValue(); - NamespaceLike namespaceDescriptor = namespaceDescriptors.get(namespace); - - resolveFunctionAndPropertyHeaders(namespace.getDeclarations(), namespaceScope, namespaceDescriptor); - } - for (Map.Entry entry : classes.entrySet()) { - JetClass jetClass = entry.getKey(); - MutableClassDescriptor classDescriptor = entry.getValue(); - - resolveFunctionAndPropertyHeaders(jetClass.getDeclarations(), classDescriptor.getScopeForMemberResolution(), classDescriptor); -// processPrimaryConstructor(classDescriptor, jetClass); -// for (JetConstructor jetConstructor : jetClass.getSecondaryConstructors()) { -// processSecondaryConstructor(classDescriptor, jetConstructor); -// } - } - for (Map.Entry entry : objects.entrySet()) { - JetObjectDeclaration object = entry.getKey(); - MutableClassDescriptor classDescriptor = entry.getValue(); - - resolveFunctionAndPropertyHeaders(object.getDeclarations(), classDescriptor.getScopeForMemberResolution(), classDescriptor); - } - - // TODO : Extensions - } - - private void resolveFunctionAndPropertyHeaders(@NotNull List declarations, final @NotNull JetScope scope, final @NotNull NamespaceLike namespaceLike) { - for (JetDeclaration declaration : declarations) { - declaration.accept(new JetVisitorVoid() { - @Override - public void visitNamedFunction(JetNamedFunction function) { - FunctionDescriptorImpl functionDescriptor = classDescriptorResolver.resolveFunctionDescriptor(namespaceLike, scope, function); - checkFunction(function, functionDescriptor, namespaceLike); - namespaceLike.addFunctionDescriptor(functionDescriptor); - functions.put(function, functionDescriptor); - declaringScopes.put(function, scope); - } - - @Override - public void visitProperty(JetProperty property) { - PropertyDescriptor propertyDescriptor = classDescriptorResolver.resolvePropertyDescriptor(namespaceLike, scope, property); - namespaceLike.addPropertyDescriptor(propertyDescriptor); - properties.put(property, propertyDescriptor); - declaringScopes.put(property, scope); - } - - @Override - public void visitObjectDeclaration(JetObjectDeclaration declaration) { - PropertyDescriptor propertyDescriptor = classDescriptorResolver.resolveObjectDeclarationAsPropertyDescriptor(namespaceLike, declaration, objects.get(declaration)); - namespaceLike.addPropertyDescriptor(propertyDescriptor); - } - - @Override - public void visitEnumEntry(JetEnumEntry enumEntry) { - if (enumEntry.getPrimaryConstructorParameterList() == null) { - PropertyDescriptor propertyDescriptor = classDescriptorResolver.resolveObjectDeclarationAsPropertyDescriptor(namespaceLike, enumEntry, classes.get(enumEntry)); - MutableClassDescriptor classObjectDescriptor = ((MutableClassDescriptor) namespaceLike).getClassObjectDescriptor(); - assert classObjectDescriptor != null; - classObjectDescriptor.addPropertyDescriptor(propertyDescriptor); - } - } - }); - } - } - - private void processPrimaryConstructor(MutableClassDescriptor classDescriptor, JetClass klass) { - if (!klass.hasPrimaryConstructor()) return; - - if (classDescriptor.getKind() == ClassKind.TRAIT) { - trace.getErrorHandler().genericError(klass.getPrimaryConstructorParameterList().getNode(), "A trait may not have a constructor"); - } - - // TODO : not all the parameters are real properties - JetScope memberScope = classDescriptor.getScopeForSupertypeResolution(); - ConstructorDescriptor constructorDescriptor = classDescriptorResolver.resolvePrimaryConstructorDescriptor(memberScope, classDescriptor, klass); - for (JetParameter parameter : klass.getPrimaryConstructorParameters()) { - PropertyDescriptor propertyDescriptor = classDescriptorResolver.resolvePrimaryConstructorParameterToAProperty( - classDescriptor, - memberScope, - parameter - ); - classDescriptor.addPropertyDescriptor(propertyDescriptor); - primaryConstructorParameterProperties.add(propertyDescriptor); - } - if (constructorDescriptor != null) { - classDescriptor.setPrimaryConstructor(constructorDescriptor); - } - } - - private void processSecondaryConstructor(MutableClassDescriptor classDescriptor, JetConstructor constructor) { - if (classDescriptor.getKind() == ClassKind.TRAIT) { - trace.getErrorHandler().genericError(constructor.getNameNode(), "A trait may not have a constructor"); - } - ConstructorDescriptor constructorDescriptor = classDescriptorResolver.resolveSecondaryConstructorDescriptor( - classDescriptor.getScopeForMemberResolution(), - classDescriptor, - constructor); - classDescriptor.addConstructor(constructorDescriptor); - constructors.put(constructor, constructorDescriptor); - declaringScopes.put(constructor, classDescriptor.getScopeForMemberLookup()); - } - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void resolveBehaviorDeclarationBodies() { - bindOverrides(); - - resolveDelegationSpecifierLists(); - resolveClassAnnotations(); - - resolveAnonymousInitializers(); - resolvePropertyDeclarationBodies(); - - resolveSecondaryConstructorBodies(); - resolveFunctionBodies(); - - checkIfPrimaryConstructorIsNecessary(); - } - - private void bindOverrides() { - for (Map.Entry entry : classes.entrySet()) { - bindOverridesInAClass(entry.getValue()); - } - for (Map.Entry entry : objects.entrySet()) { - bindOverridesInAClass(entry.getValue()); - } - } - - protected void bindOverridesInAClass(MutableClassDescriptor classDescriptor) { - - for (FunctionDescriptor declaredFunction : classDescriptor.getFunctions()) { - JetFunction function = (JetFunction) trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, declaredFunction); - assert function != null; - JetModifierList modifierList = function.getModifierList(); - ASTNode overrideNode = modifierList != null ? modifierList.getModifierNode(JetTokens.OVERRIDE_KEYWORD) : null; - boolean hasOverrideModifier = overrideNode != null; - boolean foundError = false; - for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) { - FunctionDescriptor overridden = findFunctionOverridableBy(declaredFunction, supertype); - if (overridden != null) { - if (hasOverrideModifier && !overridden.getModality().isOpen() && !foundError) { - trace.getErrorHandler().genericError(overrideNode, "Method " + overridden.getName() + " in " + overridden.getContainingDeclaration().getName() + " is final and can not be overridden"); - foundError = true; - } - ((FunctionDescriptorImpl) declaredFunction).addOverriddenFunction(overridden); - } - } - if (hasOverrideModifier && declaredFunction.getOverriddenDescriptors().size() == 0) { - trace.getErrorHandler().genericError(overrideNode, "Method " + declaredFunction.getName() + " overrides nothing"); - } - PsiElement nameIdentifier = function.getNameIdentifier(); - if (!hasOverrideModifier && declaredFunction.getOverriddenDescriptors().size() > 0 && nameIdentifier != null) { - FunctionDescriptor overriddenMethod = declaredFunction.getOverriddenDescriptors().iterator().next(); - trace.getErrorHandler().genericError(nameIdentifier.getNode(), - "Method " + declaredFunction.getName() + " overrides method " + overriddenMethod.getName() + " in class " + - overriddenMethod.getContainingDeclaration().getName() + " and needs 'override' modifier"); - } - } - } - - @Nullable - private FunctionDescriptor findFunctionOverridableBy(@NotNull FunctionDescriptor declaredFunction, @NotNull JetType supertype) { - FunctionGroup functionGroup = supertype.getMemberScope().getFunctionGroup(declaredFunction.getName()); - for (FunctionDescriptor functionDescriptor : functionGroup.getFunctionDescriptors()) { - if (FunctionDescriptorUtil.isOverridableBy(semanticServices.getTypeChecker(), functionDescriptor, declaredFunction).isSuccess()) { - return functionDescriptor; - } - } - return null; - } - - private void checkIfPrimaryConstructorIsNecessary() { - for (Map.Entry entry : classes.entrySet()) { - MutableClassDescriptor classDescriptor = entry.getValue(); - JetClass jetClass = entry.getKey(); - if (classDescriptor.getUnsubstitutedPrimaryConstructor() == null) { - for (PropertyDescriptor propertyDescriptor : classDescriptor.getProperties()) { - if (trace.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)) { - PsiElement nameIdentifier = jetClass.getNameIdentifier(); - if (nameIdentifier != null) { - trace.getErrorHandler().genericError(nameIdentifier.getNode(), - "This class must have a primary constructor, because property " + propertyDescriptor.getName() + " has a backing field"); - } - break; - } - } - } - } - } - - private void resolveDelegationSpecifierLists() { - // TODO : Make sure the same thing is not initialized twice - for (Map.Entry entry : classes.entrySet()) { - resolveDelegationSpecifierList(entry.getKey(), entry.getValue()); - } - for (Map.Entry entry : objects.entrySet()) { - resolveDelegationSpecifierList(entry.getKey(), entry.getValue()); - } - } - - private void resolveDelegationSpecifierList(final JetClassOrObject jetClass, final MutableClassDescriptor descriptor) { - final ConstructorDescriptor primaryConstructor = descriptor.getUnsubstitutedPrimaryConstructor(); - final JetScope scopeForConstructor = primaryConstructor == null - ? null - : getInnerScopeForConstructor(primaryConstructor, descriptor.getScopeForMemberResolution(), true); - final JetTypeInferrer.Services typeInferrer = semanticServices.getTypeInferrerServices(traceForConstructors, JetFlowInformationProvider.NONE); // TODO : flow - - final Map 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.getErrorHandler().genericError(specifier.getNode(), "Traits can not use delegation"); - } - JetType supertype = trace.getBindingContext().get(BindingContext.TYPE, specifier.getTypeReference()); - recordSupertype(specifier.getTypeReference(), supertype); - JetExpression delegateExpression = specifier.getDelegateExpression(); - if (delegateExpression != null) { - JetScope scope = scopeForConstructor == null - ? descriptor.getScopeForMemberResolution() - : scopeForConstructor; - JetType type = typeInferrer.getType(scope, delegateExpression, NO_EXPECTED_TYPE); - if (type != null && supertype != null && !semanticServices.getTypeChecker().isSubtypeOf(type, supertype)) { - trace.getErrorHandler().typeMismatch(delegateExpression, supertype, type); - } - } - } - - @Override - public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) { - JetValueArgumentList valueArgumentList = call.getValueArgumentList(); - ASTNode node = valueArgumentList == null ? call.getNode() : valueArgumentList.getNode(); - if (descriptor.getKind() == ClassKind.TRAIT) { - trace.getErrorHandler().genericError(node, "Traits can not initialize supertypes"); - } - JetTypeReference typeReference = call.getTypeReference(); - if (typeReference != null) { - if (descriptor.getUnsubstitutedPrimaryConstructor() != null) { - JetType supertype = typeInferrer.getCallResolver().resolveCall(trace, scopeForConstructor, null, call, NO_EXPECTED_TYPE); - if (supertype != null) { - recordSupertype(typeReference, supertype); - ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype); - if (classDescriptor != null) { - if (classDescriptor.getKind() == ClassKind.TRAIT) { - trace.getErrorHandler().genericError(node, "A trait may not have a constructor"); - } - } - } - else { - recordSupertype(typeReference, trace.getBindingContext().get(BindingContext.TYPE, typeReference)); - } - } - else if (descriptor.getKind() != ClassKind.TRAIT) { - JetType supertype = trace.getBindingContext().get(BindingContext.TYPE, typeReference); - recordSupertype(typeReference, supertype); - - assert valueArgumentList != null; - trace.getErrorHandler().genericError(valueArgumentList.getNode(), - "Class " + JetPsiUtil.safeName(jetClass.getName()) + " must have a constructor in order to be able to initialize supertypes"); - } - } - } + public void processStandardLibraryNamespace(@NotNull WritableScope outerScope, @NotNull NamespaceDescriptorImpl standardLibraryNamespace, @NotNull JetNamespace namespace) { + TypeHierarchyResolver typeHierarchyResolver = new TypeHierarchyResolver(semanticServices, trace); + typeHierarchyResolver.getNamespaceScopes().put(namespace, standardLibraryNamespace.getMemberScope()); + typeHierarchyResolver.getNamespaceDescriptors().put(namespace, standardLibraryNamespace); + typeHierarchyResolver.process(outerScope, standardLibraryNamespace, namespace.getDeclarations()); - @Override - public void visitDelegationToSuperClassSpecifier(JetDelegatorToSuperClass specifier) { - JetTypeReference typeReference = specifier.getTypeReference(); - JetType supertype = trace.getBindingContext().get(BindingContext.TYPE, typeReference); - recordSupertype(typeReference, supertype); - if (supertype != null) { - ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype); - if (classDescriptor != null) { - if (descriptor.getKind() != ClassKind.TRAIT) { - if (classDescriptor.hasConstructors() && !ErrorUtils.isError(classDescriptor.getTypeConstructor()) && classDescriptor.getKind() != ClassKind.TRAIT) { - trace.getErrorHandler().genericError(specifier.getNode(), "This type has a constructor, and thus must be initialized here"); - } - } - } - } - } + DeclarationResolver declarationResolver = new DeclarationResolver(semanticServices, trace, typeHierarchyResolver); + declarationResolver.process(); + BodyResolver bodyResolver = new BodyResolver(semanticServices, trace, typeHierarchyResolver, declarationResolver) { @Override - public void visitDelegationToThisCall(JetDelegatorToThisCall thisCall) { - throw new IllegalStateException("This-calls should be prohibited by the parser"); + protected void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor, @Nullable ClassDescriptor classDescriptor) { } @Override - public void visitJetElement(JetElement element) { - throw new UnsupportedOperationException(element.getText() + " : " + element); + protected void checkFunction(JetDeclarationWithBody function, FunctionDescriptor functionDescriptor) { } }; - - for (JetDelegationSpecifier delegationSpecifier : jetClass.getDelegationSpecifiers()) { - delegationSpecifier.accept(visitor); - } - - - Set parentEnum = Collections.emptySet(); - if (jetClass instanceof JetEnumEntry) { - parentEnum = Collections.singleton(((ClassDescriptor) descriptor.getContainingDeclaration().getContainingDeclaration()).getTypeConstructor()); - } - - checkSupertypeList(descriptor, supertypes, parentEnum); - } - - // allowedFinalSupertypes typically contains a enum type of which supertypeOwner is an entry - private void checkSupertypeList(@NotNull MutableClassDescriptor supertypeOwner, @NotNull Map supertypes, Set allowedFinalSupertypes) { - Set typeConstructors = Sets.newHashSet(); - boolean classAppeared = false; - for (Map.Entry 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.getErrorHandler().genericError(typeReference.getNode(), "Only one class may appear in a supertype list"); - } - else { - classAppeared = true; - } - } - } - else { - trace.getErrorHandler().genericError(typeReference.getNode(), "Only classes and traits may serve as supertypes"); - } - - TypeConstructor constructor = supertype.getConstructor(); - if (!typeConstructors.add(constructor)) { - trace.getErrorHandler().genericError(typeReference.getNode(), "A supertype appears twice"); - } - - if (constructor.isSealed() && !allowedFinalSupertypes.contains(constructor)) { - trace.getErrorHandler().genericError(typeReference.getNode(), "This type is final, so it cannot be inherited from"); - } - } - } - - private void resolveClassAnnotations() { - - } - - private void resolveAnonymousInitializers() { - for (Map.Entry entry : classes.entrySet()) { - resolveAnonymousInitializers(entry.getKey(), entry.getValue()); - } - for (Map.Entry entry : objects.entrySet()) { - resolveAnonymousInitializers(entry.getKey(), entry.getValue()); - } - } - - private void resolveAnonymousInitializers(JetClassOrObject jetClassOrObject, MutableClassDescriptor classDescriptor) { - List anonymousInitializers = jetClassOrObject.getAnonymousInitializers(); - if (jetClassOrObject.hasPrimaryConstructor()) { - ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); - assert primaryConstructor != null; - final JetScope scopeForConstructor = getInnerScopeForConstructor(primaryConstructor, classDescriptor.getScopeForMemberResolution(), true); - JetTypeInferrer.Services typeInferrer = semanticServices.getTypeInferrerServices(createFieldAssignTrackingTrace(), JetFlowInformationProvider.NONE); // TODO : flow - for (JetClassInitializer anonymousInitializer : anonymousInitializers) { - typeInferrer.getType(scopeForConstructor, anonymousInitializer.getBody(), NO_EXPECTED_TYPE); - } - } - else { - for (JetClassInitializer anonymousInitializer : anonymousInitializers) { - trace.getErrorHandler().genericError(anonymousInitializer.getNode(), "Anonymous initializers are only allowed in the presence of a primary constructor"); - } - } - } - - private void resolveSecondaryConstructorBodies() { - for (Map.Entry entry : constructors.entrySet()) { - JetDeclaration declaration = entry.getKey(); - ConstructorDescriptor descriptor = entry.getValue(); - - resolveSecondaryConstructorBody((JetConstructor) declaration, descriptor, ((MutableClassDescriptor) descriptor.getContainingDeclaration()).getScopeForMemberResolution()); - - assert descriptor.getReturnType() != null; - } - } - - private void resolveSecondaryConstructorBody(JetConstructor declaration, final ConstructorDescriptor descriptor, final JetScope declaringScope) { - final JetScope functionInnerScope = getInnerScopeForConstructor(descriptor, declaringScope, false); - - final JetTypeInferrer.Services typeInferrerForInitializers = semanticServices.getTypeInferrerServices(traceForConstructors, JetFlowInformationProvider.NONE); - - JetClass containingClass = PsiTreeUtil.getParentOfType(declaration, JetClass.class); - assert containingClass != null : "This must be guaranteed by the parser"; - if (!containingClass.hasPrimaryConstructor()) { - trace.getErrorHandler().genericError(declaration.getNameNode(), "A secondary constructor may appear only in a class that has a primary constructor"); - } - else { - List initializers = declaration.getInitializers(); - if (initializers.isEmpty()) { - trace.getErrorHandler().genericError(declaration.getNameNode(), "Secondary constructors must have an initializer list"); - } - else { - initializers.get(0).accept(new JetVisitorVoid() { - @Override - public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) { - JetTypeReference typeReference = call.getTypeReference(); - if (typeReference != null) { - typeInferrerForInitializers.getCallResolver().resolveCall(trace, functionInnerScope, null, call, NO_EXPECTED_TYPE); - } - } - - @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(); - - typeInferrerForInitializers.getCallResolver().resolveCall(trace, - functionInnerScope, - null, call, NO_EXPECTED_TYPE); -// call.getThisReference(), -// classDescriptor, -// classDescriptor.getDefaultType(), -// call); -// trace.getErrorHandler().genericError(call.getNode(), "this-calls are not supported"); - } - - @Override - public void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier) { - trace.getErrorHandler().genericError(specifier.getNode(), "'by'-clause is only supported for primary constructors"); - } - - @Override - public void visitDelegationToSuperClassSpecifier(JetDelegatorToSuperClass specifier) { - trace.getErrorHandler().genericError(specifier.getNode(), "Constructor parameters required"); - } - - @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.getErrorHandler().genericError(initializer.getNode(), "Only one call to 'this(...)' is allowed"); - } - } - } - JetExpression bodyExpression = declaration.getBodyExpression(); - if (bodyExpression != null) { - classDescriptorResolver.computeFlowData(declaration, bodyExpression); - JetFlowInformationProvider flowInformationProvider = classDescriptorResolver.computeFlowData(declaration, bodyExpression); - JetTypeInferrer.Services typeInferrer = semanticServices.getTypeInferrerServices(traceForConstructors, flowInformationProvider); - - typeInferrer.checkFunctionReturnType(functionInnerScope, declaration, JetStandardClasses.getUnitType()); - } - } - - @NotNull - private JetScope getInnerScopeForConstructor(@NotNull ConstructorDescriptor descriptor, @NotNull JetScope declaringScope, boolean primary) { - WritableScope constructorScope = new WritableScopeImpl(declaringScope, declaringScope.getContainingDeclaration(), trace.getErrorHandler()).setDebugName("Inner scope for constructor"); - for (PropertyDescriptor propertyDescriptor : ((MutableClassDescriptor) descriptor.getContainingDeclaration()).getProperties()) { - constructorScope.addPropertyDescriptorByFieldName("$" + propertyDescriptor.getName(), propertyDescriptor); - } - - constructorScope.setThisType(descriptor.getContainingDeclaration().getDefaultType()); - - for (ValueParameterDescriptor valueParameterDescriptor : descriptor.getValueParameters()) { - JetParameter parameter = (JetParameter) trace.getBindingContext().get(BindingContext.DESCRIPTOR_TO_DECLARATION, valueParameterDescriptor); - if (parameter.getValOrVarNode() == null || !primary) { - constructorScope.addVariableDescriptor(valueParameterDescriptor); - } - } - - constructorScope.addLabeledDeclaration(descriptor); // TODO : Labels for constructors?! - - return constructorScope; - } - - private void resolvePropertyDeclarationBodies() { - - // Member properties - Set processed = Sets.newHashSet(); - for (Map.Entry entry : classes.entrySet()) { - JetClass jetClass = entry.getKey(); - MutableClassDescriptor classDescriptor = entry.getValue(); - - for (JetProperty property : jetClass.getProperties()) { - final PropertyDescriptor propertyDescriptor = properties.get(property); - assert propertyDescriptor != null; - - JetScope declaringScope = declaringScopes.get(property); - - JetExpression initializer = property.getInitializer(); - if (initializer != null) { - ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); - if (primaryConstructor == null) { - trace.getErrorHandler().genericError(initializer.getNode(), "Property initializers are not allowed when no primary constructor is present"); - } - else { - JetScope scope = getInnerScopeForConstructor(primaryConstructor, classDescriptor.getScopeForMemberResolution(), true); - resolvePropertyInitializer(property, propertyDescriptor, initializer, scope); - } - } - - resolvePropertyAccessors(property, propertyDescriptor, declaringScope); - checkProperty(property, propertyDescriptor, classDescriptor); - processed.add(property); - } - } - - // Top-level properties & properties of objects - for (Map.Entry entry : properties.entrySet()) { - JetProperty property = entry.getKey(); - if (processed.contains(property)) continue; - - final PropertyDescriptor propertyDescriptor = entry.getValue(); - JetScope declaringScope = declaringScopes.get(property); - - JetExpression initializer = property.getInitializer(); - if (initializer != null) { - resolvePropertyInitializer(property, propertyDescriptor, initializer, declaringScope); - } - - resolvePropertyAccessors(property, propertyDescriptor, declaringScope); - checkProperty(property, propertyDescriptor, null); - } - } - - private JetScope getPropertyDeclarationInnerScope(@NotNull JetScope outerScope, @NotNull PropertyDescriptor propertyDescriptor) { - WritableScopeImpl result = new WritableScopeImpl(outerScope, propertyDescriptor, trace.getErrorHandler()).setDebugName("Property declaration inner scope"); - for (TypeParameterDescriptor typeParameterDescriptor : propertyDescriptor.getTypeParameters()) { - result.addTypeParameterDescriptor(typeParameterDescriptor); - } - JetType receiverType = propertyDescriptor.getReceiverType(); - if (receiverType != null) { - result.setThisType(receiverType); - } - return result; - } - - private void resolvePropertyAccessors(JetProperty property, PropertyDescriptor propertyDescriptor, JetScope declaringScope) { - BindingTraceAdapter fieldAccessTrackingTrace = createFieldTrackingTrace(propertyDescriptor); - - WritableScope accessorScope = new WritableScopeImpl(getPropertyDeclarationInnerScope(declaringScope, propertyDescriptor), declaringScope.getContainingDeclaration(), trace.getErrorHandler()).setDebugName("Accessor scope"); - accessorScope.addPropertyDescriptorByFieldName("$" + propertyDescriptor.getName(), propertyDescriptor); - - JetPropertyAccessor getter = property.getGetter(); - PropertyGetterDescriptor getterDescriptor = propertyDescriptor.getGetter(); - if (getter != null && getterDescriptor != null) { - resolveFunctionBody(fieldAccessTrackingTrace, getter, getterDescriptor, accessorScope); - } - - JetPropertyAccessor setter = property.getSetter(); - PropertySetterDescriptor setterDescriptor = propertyDescriptor.getSetter(); - if (setter != null && setterDescriptor != null) { - resolveFunctionBody(fieldAccessTrackingTrace, setter, setterDescriptor, accessorScope); - } - } - - protected void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor, @Nullable ClassDescriptor classDescriptor) { - JetExpression initializer = property.getInitializer(); - JetPropertyAccessor getter = property.getGetter(); - JetPropertyAccessor setter = property.getSetter(); - PsiElement nameIdentifier = property.getNameIdentifier(); - ASTNode nameNode = nameIdentifier == null ? property.getNode() : nameIdentifier.getNode(); - if (propertyDescriptor.getModality() == Modality.ABSTRACT) { - if (classDescriptor == null) { - trace.getErrorHandler().genericError(property.getModifierList().getModifierNode(JetTokens.ABSTRACT_KEYWORD), - "Global property can not be abstract"); - return; - } - if (classDescriptor.getModality() != Modality.ABSTRACT) { - trace.getErrorHandler().genericError(property.getModifierList().getModifierNode(JetTokens.ABSTRACT_KEYWORD), - "Abstract property " + property.getName() + " in non-abstract class " + classDescriptor.getName()); - return; - } - if (initializer != null) { - trace.getErrorHandler().genericError(initializer.getNode(), "Property with initializer can not be abstract"); - } - if (getter != null && getter.getBodyExpression() != null) { - trace.getErrorHandler().genericError(getter.getNode(), "Property with getter implementation can not be abstract"); - } - if (setter != null && setter.getBodyExpression() != null) { - trace.getErrorHandler().genericError(setter.getNode(), "Property with setter implementation can not be abstract"); - } - return; - } - boolean backingFieldRequired = trace.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor); - if (backingFieldRequired) { - if (initializer == null && !trace.getBindingContext().get(BindingContext.IS_INITIALIZED, propertyDescriptor)) { - if (classDescriptor == null || (getter != null && getter.getBodyExpression() != null) || (setter != null && setter.getBodyExpression() != null)) { - trace.getErrorHandler().genericError(nameNode, "Property must be initialized"); - } else if (classDescriptor.getKind() != ClassKind.TRAIT) { - trace.getErrorHandler().genericError(nameNode, "Property must be initialized or be abstract"); - } - } - } - else { - if (initializer != null) { - trace.getErrorHandler().genericError(initializer.getNode(), "Initializer is not allowed here because this property has no backing field"); - } - } - } - - protected void checkFunction(JetNamedFunction function, FunctionDescriptor functionDescriptor, DeclarationDescriptor containingDescriptor) { - PsiElement nameIdentifier = function.getNameIdentifier(); - JetModifierList modifierList = function.getModifierList(); - ASTNode abstractNode = modifierList != null ? modifierList.getModifierNode(JetTokens.ABSTRACT_KEYWORD) : null; - boolean hasAbstractModifier = abstractNode != null; - if (containingDescriptor instanceof ClassDescriptor) { - ClassDescriptor classDescriptor = (ClassDescriptor) containingDescriptor; - boolean inTrait = classDescriptor.getKind() == ClassKind.TRAIT; - boolean inEnum = classDescriptor.getKind() == ClassKind.ENUM_CLASS; - boolean inAbstractClass = classDescriptor.getModality() == Modality.ABSTRACT; - if (hasAbstractModifier && !inAbstractClass && !inTrait && !inEnum) { - trace.getErrorHandler().genericError(abstractNode, "Abstract method " + function.getName() + " in non-abstract class " + classDescriptor.getName()); - } - if (hasAbstractModifier && inTrait) { - trace.getErrorHandler().genericWarning(abstractNode, "Abstract modifier is not necessary in traits"); - } - if (function.getBodyExpression() != null && hasAbstractModifier) { - trace.getErrorHandler().genericError(abstractNode, "Method " + function.getName() + " with body can not be abstract"); - } - if (function.getBodyExpression() == null && !hasAbstractModifier && !inTrait && nameIdentifier != null) { - trace.getErrorHandler().genericError(nameIdentifier.getNode(), "Method " + function.getName() + " without body must be abstract"); - } - return; - } - if (hasAbstractModifier) { - trace.getErrorHandler().genericError(abstractNode, "Function " + function.getName() + " can not be abstract"); - } - if (function.getBodyExpression() == null && !hasAbstractModifier && nameIdentifier != null) { - trace.getErrorHandler().genericError(nameIdentifier.getNode(), "Function " + function.getName() + " must have body"); - } - } - - private BindingTraceAdapter createFieldTrackingTrace(final PropertyDescriptor propertyDescriptor) { - return new BindingTraceAdapter(traceForMembers).addHandler(BindingContext.REFERENCE_TARGET, new BindingTraceAdapter.RecordHandler() { - @Override - public void handleRecord(WritableSlice slice, JetReferenceExpression expression, DeclarationDescriptor descriptor) { - if (expression instanceof JetSimpleNameExpression) { - JetSimpleNameExpression simpleNameExpression = (JetSimpleNameExpression) expression; - if (simpleNameExpression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) { - // This check may be considered redundant as long as $x is only accessible from accessors to $x - if (descriptor == propertyDescriptor) { // TODO : original? - traceForMembers.record(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor); // TODO: this trace? - } - } - } - } - }); - } - - private BindingTraceAdapter createFieldAssignTrackingTrace() { - return new BindingTraceAdapter(traceForConstructors).addHandler(BindingContext.VARIABLE_ASSIGNMENT, new BindingTraceAdapter.RecordHandler() { - @Override - public void handleRecord(WritableSlice jetExpressionBooleanWritableSlice, JetExpression expression, DeclarationDescriptor descriptor) { - if (expression instanceof JetSimpleNameExpression) { - JetSimpleNameExpression variable = (JetSimpleNameExpression) expression; - if (variable.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) { - if (descriptor instanceof PropertyDescriptor) { - traceForMembers.record(BindingContext.IS_INITIALIZED, (PropertyDescriptor) descriptor); - } - } - } - } - }); - } - - private void resolvePropertyInitializer(JetProperty property, PropertyDescriptor propertyDescriptor, JetExpression initializer, JetScope scope) { - JetFlowInformationProvider flowInformationProvider = classDescriptorResolver.computeFlowData(property, initializer); // TODO : flow JET-15 - JetTypeInferrer.Services typeInferrer = semanticServices.getTypeInferrerServices(traceForConstructors, flowInformationProvider); - JetType type = typeInferrer.getType(getPropertyDeclarationInnerScope(scope, propertyDescriptor), initializer, NO_EXPECTED_TYPE); - - JetType expectedType = propertyDescriptor.getInType(); - if (expectedType == null) { - expectedType = propertyDescriptor.getOutType(); - } - if (type != null && expectedType != null - && !semanticServices.getTypeChecker().isSubtypeOf(type, expectedType)) { - trace.getErrorHandler().typeMismatch(initializer, expectedType, type); - } - } - - private void resolveFunctionBodies() { - for (Map.Entry entry : functions.entrySet()) { - JetDeclaration declaration = entry.getKey(); - FunctionDescriptor descriptor = entry.getValue(); - - JetScope declaringScope = declaringScopes.get(declaration); - assert declaringScope != null; - - resolveFunctionBody(traceForMembers, (JetNamedFunction) declaration, descriptor, declaringScope); - - assert descriptor.getReturnType() != null; - } - } - - private void resolveFunctionBody( - @NotNull BindingTrace trace, - @NotNull JetDeclarationWithBody function, - @NotNull FunctionDescriptor functionDescriptor, - @NotNull JetScope declaringScope) { - JetExpression bodyExpression = function.getBodyExpression(); - - if (bodyExpression != null) { - JetFlowInformationProvider flowInformationProvider = classDescriptorResolver.computeFlowData(function.asElement(), bodyExpression); - JetTypeInferrer.Services typeInferrer = semanticServices.getTypeInferrerServices(trace, flowInformationProvider); - - typeInferrer.checkFunctionReturnType(declaringScope, function, functionDescriptor); - } - - assert functionDescriptor.getReturnType() != null; + bodyResolver.resolveBehaviorDeclarationBodies(); } +} -} diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzerForStandardLibrary.java b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzerForStandardLibrary.java index 69cbe16bf9547281e5edcdb60a845d88fe1d8d12..dc1adf442c2498ef7b94a272ed83a42490dbe673 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzerForStandardLibrary.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzerForStandardLibrary.java @@ -10,22 +10,28 @@ import org.jetbrains.jet.lang.psi.JetProperty; /** * @author svtk */ -public class TopDownAnalyzerForStandardLibrary extends TopDownAnalyzer { - - public TopDownAnalyzerForStandardLibrary(JetSemanticServices semanticServices, @NotNull BindingTrace bindingTrace) { - super(semanticServices, bindingTrace); - } - - public void processStandardLibraryNamespace(@NotNull WritableScope outerScope, @NotNull NamespaceDescriptorImpl standardLibraryNamespace, @NotNull JetNamespace namespace) { - namespaceScopes.put(namespace, standardLibraryNamespace.getMemberScope()); - namespaceDescriptors.put(namespace, standardLibraryNamespace); - process(outerScope, standardLibraryNamespace, namespace.getDeclarations()); - } - - @Override - protected void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor, ClassDescriptor classDescriptor) {} - - - @Override - protected void checkFunction(JetNamedFunction function, FunctionDescriptor functionDescriptor, DeclarationDescriptor containingDescriptor) {} -} +//public class TopDownAnalyzerForStandardLibrary extends TopDownAnalyzer { +// +// public TopDownAnalyzerForStandardLibrary(JetSemanticServices semanticServices, @NotNull BindingTrace bindingTrace) { +// super(semanticServices, bindingTrace); +// } +// +// public void processStandardLibraryNamespace(@NotNull WritableScope outerScope, @NotNull NamespaceDescriptorImpl standardLibraryNamespace, @NotNull JetNamespace namespace) { +// namespaceScopes.put(namespace, standardLibraryNamespace.getMemberScope()); +// namespaceDescriptors.put(namespace, standardLibraryNamespace); +// TypeHierarchyResolver typeHierarchyResolver = new TypeHierarchyResolver(semanticServices, trace); +// typeHierarchyResolver.process(outerScope, standardLibraryNamespace, namespace.getDeclarations()); +// +// DeclarationResolver declarationResolver = new DeclarationResolver(semanticServices, trace, typeHierarchyResolver); +// declarationResolver.process(); +// +// new BodyResolver(semanticServices, trace, typeHierarchyResolver, declarationResolver).resolveBehaviorDeclarationBodies(); +// } +// +// @Override +// protected void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor, ClassDescriptor classDescriptor) {} +// +// +// @Override +// protected void checkFunction(JetNamedFunction function, FunctionDescriptor functionDescriptor, DeclarationDescriptor containingDescriptor) {} +//} diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java new file mode 100644 index 0000000000000000000000000000000000000000..7a9eaaba2ef54d6decf57543eef4c6ea0a3798a1 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java @@ -0,0 +1,328 @@ +package org.jetbrains.jet.lang.resolve; + +import com.google.common.collect.Maps; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.JetSemanticServices; +import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.JetTypeInferrer; +import org.jetbrains.jet.lexer.JetTokens; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * @author abreslav + */ +public class TypeHierarchyResolver { + + private final BindingTrace trace; + private final JetSemanticServices semanticServices; + private final ClassDescriptorResolver classDescriptorResolver; + + private final Map classes = Maps.newLinkedHashMap(); + private final Map objects = Maps.newLinkedHashMap(); + protected final Map namespaceScopes = Maps.newHashMap(); + protected final Map namespaceDescriptors = Maps.newHashMap(); + + public TypeHierarchyResolver(JetSemanticServices semanticServices, BindingTrace trace) { + this.trace = trace; + this.semanticServices = semanticServices; + this.classDescriptorResolver = semanticServices.getClassDescriptorResolver(trace); + } + + public Map getClasses() { + return classes; + } + + public Map getObjects() { + return objects; + } + + public Map getNamespaceScopes() { + return namespaceScopes; + } + + public Map getNamespaceDescriptors() { + return namespaceDescriptors; + } + + public void process(@NotNull JetScope outerScope, NamespaceLike owner, @NotNull List declarations) { + collectNamespacesAndClassifiers(outerScope, owner, declarations); // namespaceScopes, classes + + createTypeConstructors(); // create type constructors for classes and generic parameters + resolveTypesInClassHeaders(); // Generic bounds and types in supertype lists (no expressions or constructor resolution) + checkTypesInClassHeaders(); // Generic bounds and supertype lists + } + + private void collectNamespacesAndClassifiers( + @NotNull final JetScope outerScope, + @NotNull final NamespaceLike owner, + @NotNull Collection declarations) { + for (JetDeclaration declaration : declarations) { + declaration.accept(new JetVisitorVoid() { + @Override + public void visitNamespace(JetNamespace namespace) { + + String name = namespace.getName(); + if (name == null) { + name = ""; + } + NamespaceDescriptorImpl namespaceDescriptor = owner.getNamespace(name); + if (namespaceDescriptor == null) { + namespaceDescriptor = new NamespaceDescriptorImpl( + owner.getOriginal(), + Collections.emptyList(), // TODO + name + ); + namespaceDescriptor.initialize(new WritableScopeImpl(JetScope.EMPTY, namespaceDescriptor, trace.getErrorHandler()).setDebugName("Namespace member scope")); + owner.addNamespace(namespaceDescriptor); + trace.record(BindingContext.NAMESPACE, namespace, namespaceDescriptor); + } + namespaceDescriptors.put(namespace, namespaceDescriptor); + + WriteThroughScope namespaceScope = new WriteThroughScope(outerScope, namespaceDescriptor.getMemberScope(), trace.getErrorHandler()); + namespaceScopes.put(namespace, namespaceScope); + + processImports(namespace, namespaceScope, outerScope); + + collectNamespacesAndClassifiers(namespaceScope, namespaceDescriptor, namespace.getDeclarations()); + } + + @Override + public void visitClass(JetClass klass) { + MutableClassDescriptor mutableClassDescriptor = new MutableClassDescriptor(trace, owner, outerScope, getClassKind(klass)); + + if (klass.hasModifier(JetTokens.ENUM_KEYWORD)) { + MutableClassDescriptor classObjectDescriptor = new MutableClassDescriptor(trace, mutableClassDescriptor, outerScope, ClassKind.OBJECT); + classObjectDescriptor.setName("class-object-for-" + klass.getName()); + classObjectDescriptor.setModality(Modality.FINAL); + classObjectDescriptor.createTypeConstructor(); + createPrimaryConstructor(classObjectDescriptor); + mutableClassDescriptor.setClassObjectDescriptor(classObjectDescriptor); + } + visitClassOrObject( + klass, + (Map) classes, + owner, + outerScope, + mutableClassDescriptor); + owner.addClassifierDescriptor(mutableClassDescriptor); + } + + @Override + public void visitObjectDeclaration(JetObjectDeclaration declaration) { + createClassDescriptorForObject(declaration, owner); + } + + @Override + public void visitEnumEntry(JetEnumEntry enumEntry) { + MutableClassDescriptor classObjectDescriptor = ((MutableClassDescriptor) owner).getClassObjectDescriptor(); + assert classObjectDescriptor != null : enumEntry.getParent().getText(); + if (enumEntry.getPrimaryConstructorParameterList() == null) { + MutableClassDescriptor classDescriptor = createClassDescriptorForObject(enumEntry, classObjectDescriptor); + objects.remove(enumEntry); + classes.put(enumEntry, classDescriptor); + } + else { + MutableClassDescriptor mutableClassDescriptor = new MutableClassDescriptor(trace, classObjectDescriptor, outerScope, ClassKind.CLASS); // TODO : Special kind for enum entry classes? + visitClassOrObject( + enumEntry, + (Map) classes, + classObjectDescriptor, + outerScope, + mutableClassDescriptor); + classObjectDescriptor.addClassifierDescriptor(mutableClassDescriptor); + } + } + + private MutableClassDescriptor createClassDescriptorForObject(@NotNull JetClassOrObject declaration, @NotNull NamespaceLike owner) { + MutableClassDescriptor mutableClassDescriptor = new MutableClassDescriptor(trace, owner, outerScope, ClassKind.OBJECT) { + @Override + public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) { + return ClassObjectStatus.NOT_ALLOWED; + } + }; + visitClassOrObject(declaration, (Map) objects, owner, outerScope, mutableClassDescriptor); + createPrimaryConstructor(mutableClassDescriptor); + trace.record(BindingContext.CLASS, declaration, mutableClassDescriptor); + return mutableClassDescriptor; + } + + private void createPrimaryConstructor(MutableClassDescriptor mutableClassDescriptor) { + ConstructorDescriptorImpl constructorDescriptor = new ConstructorDescriptorImpl(mutableClassDescriptor, Collections.emptyList(), true); + constructorDescriptor.initialize(Collections.emptyList(), Collections.emptyList(), + Modality.FINAL); + // TODO : make the constructor private? + mutableClassDescriptor.setPrimaryConstructor(constructorDescriptor); + } + + private void visitClassOrObject(@NotNull JetClassOrObject declaration, Map map, NamespaceLike owner, JetScope outerScope, MutableClassDescriptor mutableClassDescriptor) { + mutableClassDescriptor.setName(JetPsiUtil.safeName(declaration.getName())); + + map.put(declaration, mutableClassDescriptor); +// declaringScopes.put((JetDeclaration) declaration, outerScope); + + JetScope classScope = mutableClassDescriptor.getScopeForMemberResolution(); + collectNamespacesAndClassifiers(classScope, mutableClassDescriptor, declaration.getDeclarations()); + } + + @Override + public void visitTypedef(JetTypedef typedef) { + trace.getErrorHandler().genericError(typedef.getNode(), "Unsupported [TopDownAnalyzer]"); + } + + @Override + public void visitClassObject(JetClassObject classObject) { + JetObjectDeclaration objectDeclaration = classObject.getObjectDeclaration(); + if (objectDeclaration != null) { + NamespaceLike.ClassObjectStatus status = owner.setClassObjectDescriptor(createClassDescriptorForObject(objectDeclaration, owner)); + switch (status) { + case DUPLICATE: + trace.getErrorHandler().genericError(classObject.getNode(), "Only one class object is allowed per class"); + break; + case NOT_ALLOWED: + trace.getErrorHandler().genericError(classObject.getNode(), "A class object is not allowed here"); + break; + } + } + } + }); + } + } + + @NotNull + private ClassKind getClassKind(@NotNull JetClass jetClass) { + if (jetClass.isTrait()) return ClassKind.TRAIT; + if (jetClass.hasModifier(JetTokens.ANNOTATION_KEYWORD)) return ClassKind.ANNOTATION_CLASS; + if (jetClass.hasModifier(JetTokens.ENUM_KEYWORD)) return ClassKind.ENUM_CLASS; + return ClassKind.CLASS; + } + + private void processImports(@NotNull JetNamespace namespace, @NotNull WriteThroughScope namespaceScope, @NotNull JetScope outerScope) { + List importDirectives = namespace.getImportDirectives(); + for (JetImportDirective importDirective : importDirectives) { + if (importDirective.isAbsoluteInRootNamespace()) { + trace.getErrorHandler().genericError(namespace.getNode(), "Unsupported by TDA"); // TODO + continue; + } + if (importDirective.isAllUnder()) { + JetExpression importedReference = importDirective.getImportedReference(); + if (importedReference != null) { + JetTypeInferrer.Services typeInferrerServices = semanticServices.getTypeInferrerServices(trace, JetFlowInformationProvider.THROW_EXCEPTION); + JetType type = typeInferrerServices.getTypeWithNamespaces(namespaceScope, importedReference); + if (type != null) { + namespaceScope.importScope(type.getMemberScope()); + } + } + } + else { + ClassifierDescriptor classifierDescriptor = null; + JetSimpleNameExpression referenceExpression = null; + + JetExpression importedReference = importDirective.getImportedReference(); + if (importedReference instanceof JetDotQualifiedExpression) { + JetDotQualifiedExpression reference = (JetDotQualifiedExpression) importedReference; + JetType type = semanticServices.getTypeInferrerServices(trace, JetFlowInformationProvider.THROW_EXCEPTION).getTypeWithNamespaces(namespaceScope, reference.getReceiverExpression()); + JetExpression selectorExpression = reference.getSelectorExpression(); + if (selectorExpression != null) { + referenceExpression = (JetSimpleNameExpression) selectorExpression; + String referencedName = referenceExpression.getReferencedName(); + if (type != null && referencedName != null) { + classifierDescriptor = type.getMemberScope().getClassifier(referencedName); + } + } + } + else { + assert importedReference instanceof JetSimpleNameExpression; + referenceExpression = (JetSimpleNameExpression) importedReference; + + String referencedName = referenceExpression.getReferencedName(); + if (referencedName != null) { + classifierDescriptor = outerScope.getClassifier(referencedName); + } + } + + if (classifierDescriptor != null) { + trace.record(BindingContext.REFERENCE_TARGET, referenceExpression, classifierDescriptor); + + String aliasName = importDirective.getAliasName(); + String importedClassifierName = aliasName != null ? aliasName : classifierDescriptor.getName(); + namespaceScope.importClassifierAlias(importedClassifierName, classifierDescriptor); + } + } + } + } + + private void createTypeConstructors() { + for (Map.Entry entry : classes.entrySet()) { + JetClass jetClass = entry.getKey(); + MutableClassDescriptor descriptor = entry.getValue(); + classDescriptorResolver.resolveMutableClassDescriptor(jetClass, descriptor); + descriptor.createTypeConstructor(); + } + for (Map.Entry entry : objects.entrySet()) { + MutableClassDescriptor descriptor = entry.getValue(); + descriptor.setModality(Modality.FINAL); + descriptor.createTypeConstructor(); + } + } + + private void resolveTypesInClassHeaders() { + for (Map.Entry entry : classes.entrySet()) { + JetClass jetClass = entry.getKey(); + MutableClassDescriptor descriptor = entry.getValue(); + classDescriptorResolver.resolveGenericBounds(jetClass, descriptor.getScopeForSupertypeResolution(), descriptor.getTypeConstructor().getParameters()); + classDescriptorResolver.resolveSupertypes(jetClass, descriptor); + } + for (Map.Entry entry : objects.entrySet()) { + JetClassOrObject jetClass = entry.getKey(); + MutableClassDescriptor descriptor = entry.getValue(); + classDescriptorResolver.resolveSupertypes(jetClass, descriptor); + } + } + + private void checkTypesInClassHeaders() { + for (Map.Entry entry : classes.entrySet()) { + JetClass jetClass = entry.getKey(); + + for (JetDelegationSpecifier delegationSpecifier : jetClass.getDelegationSpecifiers()) { + JetTypeReference typeReference = delegationSpecifier.getTypeReference(); + if (typeReference != null) { + JetType type = trace.getBindingContext().get(BindingContext.TYPE, typeReference); + if (type != null) { + classDescriptorResolver.checkBounds(typeReference, type); + } + } + } + + for (JetTypeParameter jetTypeParameter : jetClass.getTypeParameters()) { + JetTypeReference extendsBound = jetTypeParameter.getExtendsBound(); + if (extendsBound != null) { + JetType type = trace.getBindingContext().get(BindingContext.TYPE, extendsBound); + if (type != null) { + classDescriptorResolver.checkBounds(extendsBound, type); + } + } + } + + for (JetTypeConstraint constraint : jetClass.getTypeConstaints()) { + JetTypeReference extendsBound = constraint.getBoundTypeReference(); + if (extendsBound != null) { + JetType type = trace.getBindingContext().get(BindingContext.TYPE, extendsBound); + if (type != null) { + classDescriptorResolver.checkBounds(extendsBound, type); + } + } + } + } + } + + + +} diff --git a/idea/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java b/idea/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java index bb642d8df68399bc6b67428f5a86041735c61798..d086844c1d702f61a0fffa5fc157689246c791e4 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java @@ -97,7 +97,7 @@ public class JetStandardLibrary { JetSemanticServices bootstrappingSemanticServices = JetSemanticServices.createSemanticServices(this); BindingTraceContext bindingTraceContext = new BindingTraceContext(); - TopDownAnalyzerForStandardLibrary bootstrappingTDA = new TopDownAnalyzerForStandardLibrary(bootstrappingSemanticServices, bindingTraceContext); + TopDownAnalyzer bootstrappingTDA = new TopDownAnalyzer(bootstrappingSemanticServices, bindingTraceContext); WritableScopeImpl writableScope = new WritableScopeImpl(JetStandardClasses.STANDARD_CLASSES, JetStandardClasses.STANDARD_CLASSES_NAMESPACE, ErrorHandler.THROW_EXCEPTION).setDebugName("Root bootstrap scope"); // this.libraryScope = bootstrappingTDA.process(JetStandardClasses.STANDARD_CLASSES, file.getRootNamespace().getDeclarations()); // bootstrappingTDA.process(writableScope, JetStandardClasses.STANDARD_CLASSES_NAMESPACE, file.getRootNamespace().getDeclarations());