diff --git a/idea/src/org/jetbrains/jet/lang/JetSemanticServices.java b/idea/src/org/jetbrains/jet/lang/JetSemanticServices.java index 6c9d582c540b61057c9be98a91c09746c1a2bb8c..64bad2788630db5943696a2c1dc241283ace206f 100644 --- a/idea/src/org/jetbrains/jet/lang/JetSemanticServices.java +++ b/idea/src/org/jetbrains/jet/lang/JetSemanticServices.java @@ -3,6 +3,7 @@ package org.jetbrains.jet.lang; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; +import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.types.*; @@ -11,22 +12,28 @@ import org.jetbrains.jet.lang.types.*; */ public class JetSemanticServices { public static JetSemanticServices createSemanticServices(JetStandardLibrary standardLibrary) { - return new JetSemanticServices(standardLibrary); + return new JetSemanticServices(standardLibrary, JetControlFlowDataTraceFactory.EMPTY); } public static JetSemanticServices createSemanticServices(Project project) { - return new JetSemanticServices(JetStandardLibrary.getJetStandardLibrary(project)); + return new JetSemanticServices(JetStandardLibrary.getJetStandardLibrary(project), JetControlFlowDataTraceFactory.EMPTY); + } + + public static JetSemanticServices createSemanticServices(Project project, JetControlFlowDataTraceFactory flowDataTraceFactory) { + return new JetSemanticServices(JetStandardLibrary.getJetStandardLibrary(project), flowDataTraceFactory); } private final JetStandardLibrary standardLibrary; private final JetTypeChecker typeChecker; private final OverloadResolver overloadResolver; + private final JetControlFlowDataTraceFactory flowDataTraceFactory; - private JetSemanticServices(JetStandardLibrary standardLibrary) { + private JetSemanticServices(JetStandardLibrary standardLibrary, JetControlFlowDataTraceFactory flowDataTraceFactory) { this.standardLibrary = standardLibrary; this.typeChecker = new JetTypeChecker(standardLibrary); this.overloadResolver = new OverloadResolver(typeChecker); + this.flowDataTraceFactory = flowDataTraceFactory; } @NotNull @@ -36,7 +43,7 @@ public class JetSemanticServices { @NotNull public ClassDescriptorResolver getClassDescriptorResolver(BindingTrace trace) { - return new ClassDescriptorResolver(this, trace); + return new ClassDescriptorResolver(this, trace, flowDataTraceFactory); } @NotNull diff --git a/idea/src/org/jetbrains/jet/lang/annotations/JetLineMarkerProvider.java b/idea/src/org/jetbrains/jet/lang/annotations/JetLineMarkerProvider.java index 0dd74792faa3b2f5898076b44e8803b022833ee7..446cbcd4b3b686916e38ca18c51a14222cfc422f 100644 --- a/idea/src/org/jetbrains/jet/lang/annotations/JetLineMarkerProvider.java +++ b/idea/src/org/jetbrains/jet/lang/annotations/JetLineMarkerProvider.java @@ -47,6 +47,7 @@ public class JetLineMarkerProvider implements LineMarkerProvider { assert file != null; final BindingContext bindingContext = AnalyzingUtils.analyzeFileWithCache(file); FunctionDescriptor functionDescriptor = bindingContext.getFunctionDescriptor(jetFunction); + if (functionDescriptor == null) return null; final Set overriddenFunctions = functionDescriptor.getOverriddenFunctions(); if (!overriddenFunctions.isEmpty()) { return new LineMarkerInfo( diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java b/idea/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java index 759c48789264556023191bb0596b28c192b8c330..83b7e1a64be3f4621f42194bc18b7dd4b66eb866 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java @@ -23,33 +23,26 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme private TypeConstructor typeConstructor; - private final WritableScope classHeaderScope; - private final WritableScope writableMemberScope; - private JetScope unsubstitutedMemberScope; + private final WritableScope scopeForMemberResolution; + private final WritableScope scopeForMemberLookup; public MutableClassDescriptor(@NotNull BindingTrace trace, @NotNull DeclarationDescriptor containingDeclaration, @NotNull JetScope outerScope) { super(containingDeclaration); - this.classHeaderScope = new WritableScopeImpl(outerScope, this, trace.getErrorHandler(), null); - this.writableMemberScope = new WritableScopeImpl(classHeaderScope, this, trace.getErrorHandler(), new DeclarationDescriptorVisitor() { - @Override - public Void visitPropertyDescriptor(PropertyDescriptor descriptor, WritableScope data) { - properties.add(descriptor); - return null; - } - - @Override - public Void visitFunctionDescriptor(FunctionDescriptor descriptor, WritableScope data) { - functions.add(descriptor); - return null; - } - }); - this.unsubstitutedMemberScope = this.writableMemberScope; - } - - public MutableClassDescriptor(@NotNull DeclarationDescriptor containingDeclaration) { - super(containingDeclaration); - this.classHeaderScope = null; - this.writableMemberScope = null; + this.scopeForMemberResolution = new WritableScopeImpl(outerScope, this, trace.getErrorHandler(), null); + this.scopeForMemberLookup = new WritableScopeImpl(scopeForMemberResolution, this, trace.getErrorHandler(), null); +// this.scopeForMemberLookup = new WritableScopeImpl(scopeForMemberResolution, this, trace.getErrorHandler(), new DeclarationDescriptorVisitor() { +// @Override +// public Void visitPropertyDescriptor(PropertyDescriptor descriptor, WritableScope data) { +// properties.add(descriptor); +// return null; +// } +// +// @Override +// public Void visitFunctionDescriptor(FunctionDescriptor descriptor, WritableScope data) { +// functions.add(descriptor); +// return null; +// } +// }); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -74,6 +67,8 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme @Override public void addPropertyDescriptor(@NotNull PropertyDescriptor propertyDescriptor) { properties.add(propertyDescriptor); + scopeForMemberLookup.addVariableDescriptor(propertyDescriptor); + scopeForMemberResolution.addVariableDescriptor(propertyDescriptor); } @NotNull @@ -84,6 +79,8 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme @Override public void addFunctionDescriptor(@NotNull FunctionDescriptor functionDescriptor) { functions.add(functionDescriptor); + scopeForMemberLookup.addFunctionDescriptor(functionDescriptor); + scopeForMemberResolution.addFunctionDescriptor(functionDescriptor); } @NotNull @@ -104,15 +101,12 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme @Override public void addClassifierDescriptor(@NotNull MutableClassDescriptor classDescriptor) { classes.add(classDescriptor); + scopeForMemberLookup.addClassifierDescriptor(classDescriptor); + scopeForMemberResolution.addClassifierDescriptor(classDescriptor); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - public void setUnsubstitutedMemberScope(@NotNull JetScope unsubstitutedMemberScope) { - assert writableMemberScope == null; - this.unsubstitutedMemberScope = unsubstitutedMemberScope; - } - @NotNull @Override public TypeConstructor getTypeConstructor() { @@ -128,18 +122,17 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme @Override public JetScope getMemberScope(List typeArguments) { assert typeArguments.size() == typeConstructor.getParameters().size(); - assert unsubstitutedMemberScope != null; - if (typeArguments.isEmpty()) return unsubstitutedMemberScope; + if (typeArguments.isEmpty()) return scopeForMemberLookup; List typeParameters = getTypeConstructor().getParameters(); Map substitutionContext = TypeUtils.buildSubstitutionContext(typeParameters, typeArguments); - return new SubstitutingScope(unsubstitutedMemberScope, TypeSubstitutor.create(substitutionContext)); + return new SubstitutingScope(scopeForMemberLookup, TypeSubstitutor.create(substitutionContext)); } @NotNull @Override public JetType getDefaultType() { - return TypeUtils.makeUnsubstitutedType(this, unsubstitutedMemberScope); + return TypeUtils.makeUnsubstitutedType(this, scopeForMemberLookup); } @NotNull @@ -156,13 +149,13 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme } @NotNull - public WritableScope getWritableUnsubstitutedMemberScope() { - return writableMemberScope; + public WritableScope getScopeForMemberLookup() { + return scopeForMemberLookup; } @NotNull - public WritableScope getClassHeaderScope() { - return classHeaderScope; + public WritableScope getScopeForMemberResolution() { + return scopeForMemberResolution; } @NotNull diff --git a/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java b/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java index 664121f8dc4acaa89ff524f067e8a0bb1b581441..3f122e22bf539dcb1a78342a39e32e32fd795011 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java @@ -1,5 +1,6 @@ package org.jetbrains.jet.lang.resolve; +import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Key; import com.intellij.psi.PsiElement; @@ -29,16 +30,29 @@ import java.util.Collections; public class AnalyzingUtils { private final static Key> BINDING_CONTEXT = Key.create("BINDING_CONTEXT"); + synchronized // TODO public static BindingContext analyzeFileWithCache(@NotNull final JetFile file) { // TODO : Synchronization? CachedValue bindingContextCachedValue = file.getUserData(BINDING_CONTEXT); if (bindingContextCachedValue == null) { bindingContextCachedValue = CachedValuesManager.getManager(file.getProject()).createCachedValue(new CachedValueProvider() { @Override + synchronized // TODO : make it more granular public Result compute() { - JetNamespace rootNamespace = file.getRootNamespace(); - BindingContext bindingContext = analyzeNamespace(rootNamespace, JetControlFlowDataTraceFactory.EMPTY); - return new Result(bindingContext, PsiModificationTracker.MODIFICATION_COUNT); + try { + JetNamespace rootNamespace = file.getRootNamespace(); + BindingContext bindingContext = analyzeNamespace(rootNamespace, JetControlFlowDataTraceFactory.EMPTY); + return new Result(bindingContext, PsiModificationTracker.MODIFICATION_COUNT); + } + catch (ProcessCanceledException e) { + throw e; + } + catch (Throwable e) { + e.printStackTrace(); + BindingTraceContext bindingTraceContext = new BindingTraceContext(); + bindingTraceContext.getErrorHandler().genericError(file.getNode(), e.getClass().getSimpleName() + ": " + e.getMessage()); + return new Result(bindingTraceContext, PsiModificationTracker.MODIFICATION_COUNT); + } } }, false); file.putUserData(BINDING_CONTEXT, bindingContextCachedValue); @@ -50,7 +64,7 @@ public class AnalyzingUtils { Project project = namespace.getProject(); BindingTraceContext bindingTraceContext = new BindingTraceContext(); - JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(project); + JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(project, flowDataTraceFactory); JavaSemanticServices javaSemanticServices = new JavaSemanticServices(project, semanticServices, bindingTraceContext); JetScope libraryScope = semanticServices.getStandardLibrary().getLibraryScope(); @@ -61,7 +75,7 @@ public class AnalyzingUtils { scope.importScope(new JavaPackageScope("", null, javaSemanticServices)); scope.importScope(new JavaPackageScope("java.lang", null, javaSemanticServices)); - TopDownAnalyzer topDownAnalyzer = new TopDownAnalyzer(semanticServices, bindingTraceContext, flowDataTraceFactory); + TopDownAnalyzer topDownAnalyzer = new TopDownAnalyzer(semanticServices, bindingTraceContext); // topDownAnalyzer.process(scope, Collections.singletonList(namespace)); // if (false) topDownAnalyzer.process(scope, new NamespaceLike.Adapter(owner) { diff --git a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java index d8a19259147fc30aab5bd592935c21215cd1e42a..6e1076d1b0c922f9f9da11f5f81d2ac768a46dcb 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java @@ -5,16 +5,15 @@ import com.intellij.lang.ASTNode; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.JetSemanticServices; +import org.jetbrains.jet.lang.cfg.JetControlFlowProcessor; import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; +import org.jetbrains.jet.lang.cfg.pseudocode.*; 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 java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; +import java.util.*; /** * @author abreslav @@ -27,12 +26,14 @@ public class ClassDescriptorResolver { private final TypeResolver typeResolver; private final TypeResolver typeResolverNotCheckingBounds; private final BindingTrace trace; + private final JetControlFlowDataTraceFactory flowDataTraceFactory; - public ClassDescriptorResolver(JetSemanticServices semanticServices, BindingTrace trace) { + public ClassDescriptorResolver(JetSemanticServices semanticServices, BindingTrace trace, JetControlFlowDataTraceFactory flowDataTraceFactory) { this.semanticServices = semanticServices; this.typeResolver = new TypeResolver(semanticServices, trace, true); this.typeResolverNotCheckingBounds = new TypeResolver(semanticServices, trace, false); this.trace = trace; + this.flowDataTraceFactory = flowDataTraceFactory; } @Nullable @@ -78,9 +79,9 @@ public class ClassDescriptorResolver { public void resolveMutableClassDescriptor(@NotNull JetClass classElement, @NotNull MutableClassDescriptor descriptor) { descriptor.setName(JetPsiUtil.safeName(classElement.getName())); - descriptor.getClassHeaderScope().addLabeledDeclaration(descriptor); + descriptor.getScopeForMemberResolution().addLabeledDeclaration(descriptor); - WritableScope parameterScope = descriptor.getClassHeaderScope(); + WritableScope scopeForMemberResolution = descriptor.getScopeForMemberResolution(); // TODO : Where-clause List typeParameters = Lists.newArrayList(); @@ -91,7 +92,7 @@ public class ClassDescriptorResolver { typeParameter.getVariance(), JetPsiUtil.safeName(typeParameter.getName()) ); - parameterScope.addTypeParameterDescriptor(typeParameterDescriptor); + scopeForMemberResolution.addTypeParameterDescriptor(typeParameterDescriptor); trace.recordDeclarationResolution(typeParameter, typeParameterDescriptor); typeParameters.add(typeParameterDescriptor); } @@ -109,7 +110,7 @@ public class ClassDescriptorResolver { typeConstructor ); - descriptor.getClassHeaderScope().setThisType(descriptor.getDefaultType()); + descriptor.getScopeForMemberResolution().setThisType(descriptor.getDefaultType()); trace.recordDeclarationResolution(classElement, descriptor); } @@ -122,7 +123,7 @@ public class ClassDescriptorResolver { TypeParameterDescriptor typeParameterDescriptor = parameters.get(i); JetTypeReference extendsBound = jetTypeParameter.getExtendsBound(); if (extendsBound != null) { - typeParameterDescriptor.addUpperBound(typeResolverNotCheckingBounds.resolveType(classDescriptor.getClassHeaderScope(), extendsBound)); + typeParameterDescriptor.addUpperBound(typeResolverNotCheckingBounds.resolveType(classDescriptor.getScopeForMemberResolution(), extendsBound)); } else { typeParameterDescriptor.addUpperBound(JetStandardClasses.getDefaultBound()); @@ -136,15 +137,21 @@ public class ClassDescriptorResolver { // TODO : assuming that the hierarchy is acyclic Collection superclasses = delegationSpecifiers.isEmpty() ? Collections.singleton(JetStandardClasses.getAnyType()) - : resolveDelegationSpecifiers(descriptor.getClassHeaderScope(), delegationSpecifiers, typeResolverNotCheckingBounds); + : resolveDelegationSpecifiers(descriptor.getScopeForMemberResolution(), delegationSpecifiers, typeResolverNotCheckingBounds); ((TypeConstructorImpl) descriptor.getTypeConstructor()).getSupertypes().addAll(superclasses); + + // TODO : remove the importing + for (JetType superclass : superclasses) { + descriptor.getScopeForMemberResolution().importScope(superclass.getMemberScope()); + + } } public void resolveMutableClassDescriptor(@NotNull JetScope scope, @NotNull JetClass classElement, @NotNull MutableClassDescriptor descriptor) { descriptor.setName(JetPsiUtil.safeName(classElement.getName())); - descriptor.getClassHeaderScope().addLabeledDeclaration(descriptor); + descriptor.getScopeForMemberResolution().addLabeledDeclaration(descriptor); - WritableScope parameterScope = descriptor.getClassHeaderScope(); + WritableScope parameterScope = descriptor.getScopeForMemberResolution(); // This call has side-effects on the parameterScope (fills it in) List typeParameters @@ -179,7 +186,7 @@ public class ClassDescriptorResolver { parameterScope.importScope(supertype.getMemberScope()); } - descriptor.getClassHeaderScope().setThisType(descriptor.getDefaultType()); + descriptor.getScopeForMemberResolution().setThisType(descriptor.getDefaultType()); trace.recordDeclarationResolution(classElement, descriptor); } @@ -228,8 +235,8 @@ public class ClassDescriptorResolver { } @NotNull - public FunctionDescriptorImpl resolveFunctionDescriptor(DeclarationDescriptor containingDescriptor, JetScope scope, JetFunction function) { - FunctionDescriptorImpl functionDescriptor = new FunctionDescriptorImpl( + public FunctionDescriptorImpl resolveFunctionDescriptor(DeclarationDescriptor containingDescriptor, final JetScope scope, final JetFunction function) { + final FunctionDescriptorImpl functionDescriptor = new FunctionDescriptorImpl( containingDescriptor, AnnotationResolver.INSTANCE.resolveAnnotations(function.getModifierList()), JetPsiUtil.safeName(function.getName()) @@ -246,6 +253,18 @@ public class ClassDescriptorResolver { if (returnTypeRef != null) { returnType = typeResolver.resolveType(innerScope, returnTypeRef); } + else { + final JetExpression bodyExpression = function.getBodyExpression(); + if (bodyExpression != null) { + returnType = new DeferredType(new LazyValue() { + @Override + protected JetType compute() { + JetFlowInformationProvider flowInformationProvider = computeFlowData(function.asElement(), bodyExpression); + return semanticServices.getTypeInferrer(trace, flowInformationProvider).getFunctionReturnType(scope, function, functionDescriptor); + } + }); + } + } functionDescriptor.initialize( typeParameterDescriptors, @@ -625,4 +644,158 @@ public class ClassDescriptorResolver { } } } + + public JetFlowInformationProvider computeFlowData(@NotNull JetElement declaration, @NotNull JetExpression bodyExpression) { + final JetPseudocodeTrace pseudocodeTrace = flowDataTraceFactory.createTrace(declaration); + final Map pseudocodeMap = new HashMap(); + final Map representativeInstructions = new HashMap(); + JetPseudocodeTrace wrappedTrace = new JetPseudocodeTrace() { + @Override + public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) { + pseudocodeTrace.recordControlFlowData(element, pseudocode); + pseudocodeMap.put(element, pseudocode); + } + + @Override + public void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction) { + Instruction oldValue = representativeInstructions.put(element, instruction); +// assert oldValue == null : element.getText(); + } + + @Override + public void close() { + pseudocodeTrace.close(); + for (Pseudocode pseudocode : pseudocodeMap.values()) { + pseudocode.postProcess(); + } + } + }; + JetControlFlowInstructionsGenerator instructionsGenerator = new JetControlFlowInstructionsGenerator(wrappedTrace); + new JetControlFlowProcessor(semanticServices, trace, instructionsGenerator).generate(declaration, bodyExpression); + wrappedTrace.close(); + return new JetFlowInformationProvider() { + @Override + public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection returnedExpressions, @NotNull Collection elementsReturningUnit) { + Pseudocode pseudocode = pseudocodeMap.get(subroutine); + assert pseudocode != null; + + SubroutineExitInstruction exitInstruction = pseudocode.getExitInstruction(); + processPreviousInstructions(exitInstruction, new HashSet(), returnedExpressions, elementsReturningUnit); + } + + @Override + public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection unreachableElements) { + Pseudocode pseudocode = pseudocodeMap.get(subroutine); + assert pseudocode != null; + + SubroutineEnterInstruction enterInstruction = pseudocode.getEnterInstruction(); + Set visited = new HashSet(); + collectReachable(enterInstruction, visited); + + for (Instruction instruction : pseudocode.getInstructions()) { + if (!visited.contains(instruction) && + instruction instanceof JetElementInstruction && + // TODO : do {return} while (1 > a) + !(instruction instanceof ReadUnitValueInstruction)) { + unreachableElements.add(((JetElementInstruction) instruction).getElement()); + } + } + } + + @Override + public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection dominated) { + Instruction dominatorInstruction = representativeInstructions.get(dominator); + if (dominatorInstruction == null) { + return; + } + SubroutineEnterInstruction enterInstruction = dominatorInstruction.getOwner().getEnterInstruction(); + + Set reachable = new HashSet(); + collectReachable(enterInstruction, reachable); + + Set reachableWithDominatorProhibited = new HashSet(); + reachableWithDominatorProhibited.add(dominatorInstruction); + collectReachable(enterInstruction, reachableWithDominatorProhibited); + + for (Instruction instruction : reachable) { + if (instruction instanceof JetElementInstruction + && reachable.contains(instruction) + && !reachableWithDominatorProhibited.contains(instruction)) { + JetElementInstruction elementInstruction = (JetElementInstruction) instruction; + dominated.add(elementInstruction.getElement()); + } + } + } + }; + } + + private void collectReachable(Instruction current, Set visited) { + if (!visited.add(current)) return; + + for (Instruction nextInstruction : current.getNextInstructions()) { + collectReachable(nextInstruction, visited); + } + } + + private void processPreviousInstructions(Instruction previousFor, final Set visited, final Collection returnedExpressions, final Collection elementsReturningUnit) { + if (!visited.add(previousFor)) return; + + Collection previousInstructions = previousFor.getPreviousInstructions(); + InstructionVisitor visitor = new InstructionVisitor() { + @Override + public void visitReadValue(ReadValueInstruction instruction) { + returnedExpressions.add((JetExpression) instruction.getElement()); + } + + @Override + public void visitReturnValue(ReturnValueInstruction instruction) { + processPreviousInstructions(instruction, visited, returnedExpressions, elementsReturningUnit); + } + + @Override + public void visitReturnNoValue(ReturnNoValueInstruction instruction) { + elementsReturningUnit.add(instruction.getElement()); + } + + @Override + public void visitSubroutineEnter(SubroutineEnterInstruction instruction) { + elementsReturningUnit.add(instruction.getSubroutine()); + } + + @Override + public void visitUnsupportedElementInstruction(UnsupportedElementInstruction instruction) { + trace.getErrorHandler().genericError(instruction.getElement().getNode(), "Unsupported by control-flow builder " + instruction.getElement()); + } + + @Override + public void visitWriteValue(WriteValueInstruction writeValueInstruction) { + elementsReturningUnit.add(writeValueInstruction.getElement()); + } + + @Override + public void visitJump(AbstractJumpInstruction instruction) { + processPreviousInstructions(instruction, visited, returnedExpressions, elementsReturningUnit); + } + + @Override + public void visitReadUnitValue(ReadUnitValueInstruction instruction) { + returnedExpressions.add((JetExpression) instruction.getElement()); + } + + @Override + public void visitInstruction(Instruction instruction) { + if (instruction instanceof JetElementInstructionImpl) { + JetElementInstructionImpl elementInstruction = (JetElementInstructionImpl) instruction; + trace.getErrorHandler().genericError(elementInstruction.getElement().getNode(), "Unsupported by control-flow builder " + elementInstruction.getElement()); + } + else { + throw new UnsupportedOperationException(instruction.toString()); + } + } + }; + for (Instruction previousInstruction : previousInstructions) { + previousInstruction.accept(visitor); + } + } + } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index ddeaf1b6a4deee3e60e8d55b48f265e7e9913b2d..8b22941836a712bc1f9cbcf3450a3c688e45305e 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -9,9 +9,7 @@ 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.JetControlFlowProcessor; import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; -import org.jetbrains.jet.lang.cfg.pseudocode.*; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.types.*; @@ -38,16 +36,14 @@ public class TopDownAnalyzer { private final JetSemanticServices semanticServices; private final ClassDescriptorResolver classDescriptorResolver; private final BindingTraceContext trace; - private final JetControlFlowDataTraceFactory flowDataTraceFactory; private boolean readyToProcessExpressions = false; private final BindingTraceAdapter traceForConstructors; private final BindingTraceAdapter traceForMembers; - public TopDownAnalyzer(JetSemanticServices semanticServices, @NotNull BindingTraceContext bindingTrace, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) { + public TopDownAnalyzer(JetSemanticServices semanticServices, @NotNull BindingTraceContext bindingTrace) { this.semanticServices = semanticServices; - this.classDescriptorResolver = new ClassDescriptorResolver(semanticServices, bindingTrace); + this.classDescriptorResolver = semanticServices.getClassDescriptorResolver(bindingTrace); this.trace = bindingTrace; - this.flowDataTraceFactory = flowDataTraceFactory; // This allows access to backing fields this.traceForConstructors = new BindingTraceAdapter(bindingTrace) { @@ -80,10 +76,6 @@ public class TopDownAnalyzer { }; } - public TopDownAnalyzer(JetSemanticServices semanticServices, @NotNull BindingTraceContext bindingTrace) { - this(semanticServices, bindingTrace, JetControlFlowDataTraceFactory.EMPTY); - } - // public void process(@NotNull JetScope outerScope, @NotNull JetDeclaration declaration) { // process(outerScope, Collections.singletonList(declaration)); // } @@ -96,6 +88,8 @@ public class TopDownAnalyzer { checkGenericBoundsInClassHeaders(); // For the types resolved so far resolveFunctionAndPropertyHeaders(declarations); // TODO : for now, fail fast if something is unknown yet (i.e. some type annotation is omitted) + // Constructor headers are resolved as well + resolveExecutableCode(); // processBehaviorDeclarators(outerScope, declarations); @@ -164,8 +158,8 @@ public class TopDownAnalyzer { classes.put(klass, mutableClassDescriptor); declaringScopes.put(klass, outerScope); - WritableScope classScope = mutableClassDescriptor.getWritableUnsubstitutedMemberScope(); - collectTypeDeclarators(classScope, klass.getDeclarations()); + WritableScope classScope = mutableClassDescriptor.getScopeForMemberResolution(); + collectNamespacesAndClassifiers(classScope, mutableClassDescriptor, klass.getDeclarations()); } @Override @@ -232,9 +226,12 @@ public class TopDownAnalyzer { JetClass jetClass = entry.getKey(); final MutableClassDescriptor classDescriptor = entry.getValue(); - resolveFunctionAndPropertyHeaders(jetClass.getDeclarations(), classDescriptor.getClassHeaderScope(), classDescriptor); + resolveFunctionAndPropertyHeaders(jetClass.getDeclarations(), classDescriptor.getScopeForMemberResolution(), classDescriptor); processPrimaryConstructor(classDescriptor, jetClass); -// processBehaviorDeclarators(classDescriptor.getWritableUnsubstitutedMemberScope(), jetClass.getDeclarations()); + for (JetConstructor jetConstructor : jetClass.getSecondaryConstructors()) { + processSecondaryConstructor(classDescriptor, jetConstructor); + } +// processBehaviorDeclarators(classDescriptor.getScopeForMemberLookup(), jetClass.getDeclarations()); // TODO : Constructors } @@ -341,7 +338,7 @@ public class TopDownAnalyzer { classes.put(klass, mutableClassDescriptor); declaringScopes.put(klass, declaringScope); - WritableScope classScope = mutableClassDescriptor.getWritableUnsubstitutedMemberScope(); + WritableScope classScope = mutableClassDescriptor.getScopeForMemberLookup(); collectTypeDeclarators(classScope, klass.getDeclarations()); } @@ -382,7 +379,7 @@ public class TopDownAnalyzer { public void visitClass(JetClass klass) { MutableClassDescriptor mutableClassDescriptor = classes.get(klass); processPrimaryConstructor(mutableClassDescriptor, klass); - processBehaviorDeclarators(mutableClassDescriptor.getWritableUnsubstitutedMemberScope(), klass.getDeclarations()); + processBehaviorDeclarators(mutableClassDescriptor.getScopeForMemberLookup(), klass.getDeclarations()); } @Override @@ -436,7 +433,7 @@ public class TopDownAnalyzer { if (!klass.hasPrimaryConstructor()) return; // TODO : not all the parameters are real properties - WritableScope memberScope = classDescriptor.getWritableUnsubstitutedMemberScope(); // TODO : this is REALLY questionable + WritableScope memberScope = classDescriptor.getScopeForMemberLookup(); // TODO : this is REALLY questionable ConstructorDescriptor constructorDescriptor = classDescriptorResolver.resolvePrimaryConstructorDescriptor(memberScope, classDescriptor, klass); for (JetParameter parameter : klass.getPrimaryConstructorParameters()) { PropertyDescriptor propertyDescriptor = classDescriptorResolver.resolvePrimaryConstructorParameterToAProperty( @@ -455,12 +452,12 @@ public class TopDownAnalyzer { private void processSecondaryConstructor(MutableClassDescriptor classDescriptor, JetConstructor constructor) { ConstructorDescriptor constructorDescriptor = classDescriptorResolver.resolveSecondaryConstructorDescriptor( - classDescriptor.getWritableUnsubstitutedMemberScope(), + classDescriptor.getScopeForMemberLookup(), classDescriptor, constructor); classDescriptor.addConstructor(constructorDescriptor); constructors.put(constructor, constructorDescriptor); - declaringScopes.put(constructor, classDescriptor.getWritableUnsubstitutedMemberScope()); + declaringScopes.put(constructor, classDescriptor.getScopeForMemberLookup()); } private void processFunction(@NotNull WritableScope declaringScope, JetFunction function) { @@ -553,7 +550,7 @@ public class TopDownAnalyzer { final JetClass jetClass = entry.getKey(); final MutableClassDescriptor descriptor = entry.getValue(); final ConstructorDescriptor primaryConstructor = descriptor.getUnsubstitutedPrimaryConstructor(); - final JetScope scopeForConstructor = primaryConstructor == null ? null : getInnerScopeForConstructor(primaryConstructor, descriptor.getWritableUnsubstitutedMemberScope()); + final JetScope scopeForConstructor = primaryConstructor == null ? null : getInnerScopeForConstructor(primaryConstructor, descriptor.getScopeForMemberLookup()); final JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(traceForConstructors, JetFlowInformationProvider.NONE); // TODO : flow for (JetDelegationSpecifier delegationSpecifier : jetClass.getDelegationSpecifiers()) { @@ -562,7 +559,7 @@ public class TopDownAnalyzer { public void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier) { JetExpression delegateExpression = specifier.getDelegateExpression(); if (delegateExpression != null) { - JetScope scope = scopeForConstructor == null ? descriptor.getWritableUnsubstitutedMemberScope() : scopeForConstructor; + JetScope scope = scopeForConstructor == null ? descriptor.getScopeForMemberLookup() : scopeForConstructor; JetType type = typeInferrer.getType(scope, delegateExpression, false); JetType supertype = trace.resolveTypeReference(specifier.getTypeReference()); if (type != null && !semanticServices.getTypeChecker().isSubtypeOf(type, supertype)) { // TODO : Convertible? @@ -628,7 +625,7 @@ public class TopDownAnalyzer { if (jetClass.hasPrimaryConstructor()) { ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); assert primaryConstructor != null; - final JetScope scopeForConstructor = getInnerScopeForConstructor(primaryConstructor, classDescriptor.getWritableUnsubstitutedMemberScope()); + final JetScope scopeForConstructor = getInnerScopeForConstructor(primaryConstructor, classDescriptor.getScopeForMemberLookup()); JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(traceForConstructors, JetFlowInformationProvider.NONE); // TODO : flow for (JetClassInitializer anonymousInitializer : anonymousInitializers) { typeInferrer.getType(scopeForConstructor, anonymousInitializer.getBody(), true); @@ -717,8 +714,8 @@ public class TopDownAnalyzer { } JetExpression bodyExpression = declaration.getBodyExpression(); if (bodyExpression != null) { - computeFlowData(declaration, bodyExpression); - JetFlowInformationProvider flowInformationProvider = computeFlowData(declaration, bodyExpression); + classDescriptorResolver.computeFlowData(declaration, bodyExpression); + JetFlowInformationProvider flowInformationProvider = classDescriptorResolver.computeFlowData(declaration, bodyExpression); JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(traceForConstructors, flowInformationProvider); typeInferrer.getType(functionInnerScope, bodyExpression, true); @@ -755,7 +752,7 @@ public class TopDownAnalyzer { trace.getErrorHandler().genericError(initializer.getNode(), "Property initializers are not allowed when no primary constructor is present"); } else { - JetScope scope = getInnerScopeForConstructor(primaryConstructor, classDescriptor.getWritableUnsubstitutedMemberScope()); + JetScope scope = getInnerScopeForConstructor(primaryConstructor, classDescriptor.getScopeForMemberLookup()); resolvePropertyInitializer(property, propertyDescriptor, initializer, scope); } } @@ -825,7 +822,7 @@ public class TopDownAnalyzer { } private void resolvePropertyInitializer(JetProperty property, PropertyDescriptor propertyDescriptor, JetExpression initializer, JetScope scope) { - JetFlowInformationProvider flowInformationProvider = computeFlowData(property, initializer); // TODO : flow JET-15 + JetFlowInformationProvider flowInformationProvider = classDescriptorResolver.computeFlowData(property, initializer); // TODO : flow JET-15 JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(traceForConstructors, flowInformationProvider); JetType type = typeInferrer.getType(scope, initializer, false); @@ -867,7 +864,7 @@ public class TopDownAnalyzer { @NotNull JetScope declaringScope) { JetExpression bodyExpression = function.getBodyExpression(); if (bodyExpression != null) { - JetFlowInformationProvider flowInformationProvider = computeFlowData(function.asElement(), bodyExpression); + JetFlowInformationProvider flowInformationProvider = classDescriptorResolver.computeFlowData(function.asElement(), bodyExpression); JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(trace, flowInformationProvider); assert readyToProcessExpressions : "Must be ready collecting types"; @@ -905,157 +902,4 @@ public class TopDownAnalyzer { } } - private JetFlowInformationProvider computeFlowData(@NotNull JetElement declaration, @NotNull JetExpression bodyExpression) { - final JetPseudocodeTrace pseudocodeTrace = flowDataTraceFactory.createTrace(declaration); - final Map pseudocodeMap = new HashMap(); - final Map representativeInstructions = new HashMap(); - JetPseudocodeTrace wrappedTrace = new JetPseudocodeTrace() { - @Override - public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) { - pseudocodeTrace.recordControlFlowData(element, pseudocode); - pseudocodeMap.put(element, pseudocode); - } - - @Override - public void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction) { - Instruction oldValue = representativeInstructions.put(element, instruction); -// assert oldValue == null : element.getText(); - } - - @Override - public void close() { - pseudocodeTrace.close(); - for (Pseudocode pseudocode : pseudocodeMap.values()) { - pseudocode.postProcess(); - } - } - }; - JetControlFlowInstructionsGenerator instructionsGenerator = new JetControlFlowInstructionsGenerator(wrappedTrace); - new JetControlFlowProcessor(semanticServices, trace, instructionsGenerator).generate(declaration, bodyExpression); - wrappedTrace.close(); - return new JetFlowInformationProvider() { - @Override - public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection returnedExpressions, @NotNull Collection elementsReturningUnit) { - Pseudocode pseudocode = pseudocodeMap.get(subroutine); - assert pseudocode != null; - - SubroutineExitInstruction exitInstruction = pseudocode.getExitInstruction(); - processPreviousInstructions(exitInstruction, new HashSet(), returnedExpressions, elementsReturningUnit); - } - - @Override - public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection unreachableElements) { - Pseudocode pseudocode = pseudocodeMap.get(subroutine); - assert pseudocode != null; - - SubroutineEnterInstruction enterInstruction = pseudocode.getEnterInstruction(); - Set visited = new HashSet(); - collectReachable(enterInstruction, visited); - - for (Instruction instruction : pseudocode.getInstructions()) { - if (!visited.contains(instruction) && - instruction instanceof JetElementInstruction && - // TODO : do {return} while (1 > a) - !(instruction instanceof ReadUnitValueInstruction)) { - unreachableElements.add(((JetElementInstruction) instruction).getElement()); - } - } - } - - @Override - public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection dominated) { - Instruction dominatorInstruction = representativeInstructions.get(dominator); - if (dominatorInstruction == null) { - return; - } - SubroutineEnterInstruction enterInstruction = dominatorInstruction.getOwner().getEnterInstruction(); - - Set reachable = new HashSet(); - collectReachable(enterInstruction, reachable); - - Set reachableWithDominatorProhibited = new HashSet(); - reachableWithDominatorProhibited.add(dominatorInstruction); - collectReachable(enterInstruction, reachableWithDominatorProhibited); - - for (Instruction instruction : reachable) { - if (instruction instanceof JetElementInstruction - && reachable.contains(instruction) - && !reachableWithDominatorProhibited.contains(instruction)) { - JetElementInstruction elementInstruction = (JetElementInstruction) instruction; - dominated.add(elementInstruction.getElement()); - } - } - } - }; - } - - private void collectReachable(Instruction current, Set visited) { - if (!visited.add(current)) return; - - for (Instruction nextInstruction : current.getNextInstructions()) { - collectReachable(nextInstruction, visited); - } - } - - private void processPreviousInstructions(Instruction previousFor, final Set visited, final Collection returnedExpressions, final Collection elementsReturningUnit) { - if (!visited.add(previousFor)) return; - - Collection previousInstructions = previousFor.getPreviousInstructions(); - InstructionVisitor visitor = new InstructionVisitor() { - @Override - public void visitReadValue(ReadValueInstruction instruction) { - returnedExpressions.add((JetExpression) instruction.getElement()); - } - - @Override - public void visitReturnValue(ReturnValueInstruction instruction) { - processPreviousInstructions(instruction, visited, returnedExpressions, elementsReturningUnit); - } - - @Override - public void visitReturnNoValue(ReturnNoValueInstruction instruction) { - elementsReturningUnit.add(instruction.getElement()); - } - - @Override - public void visitSubroutineEnter(SubroutineEnterInstruction instruction) { - elementsReturningUnit.add(instruction.getSubroutine()); - } - - @Override - public void visitUnsupportedElementInstruction(UnsupportedElementInstruction instruction) { - trace.getErrorHandler().genericError(instruction.getElement().getNode(), "Unsupported by control-flow builder " + instruction.getElement()); - } - - @Override - public void visitWriteValue(WriteValueInstruction writeValueInstruction) { - elementsReturningUnit.add(writeValueInstruction.getElement()); - } - - @Override - public void visitJump(AbstractJumpInstruction instruction) { - processPreviousInstructions(instruction, visited, returnedExpressions, elementsReturningUnit); - } - - @Override - public void visitReadUnitValue(ReadUnitValueInstruction instruction) { - returnedExpressions.add((JetExpression) instruction.getElement()); - } - - @Override - public void visitInstruction(Instruction instruction) { - if (instruction instanceof JetElementInstructionImpl) { - JetElementInstructionImpl elementInstruction = (JetElementInstructionImpl) instruction; - trace.getErrorHandler().genericError(elementInstruction.getElement().getNode(), "Unsupported by control-flow builder " + elementInstruction.getElement()); - } - else { - throw new UnsupportedOperationException(instruction.toString()); - } - } - }; - for (Instruction previousInstruction : previousInstructions) { - previousInstruction.accept(visitor); - } - } - } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaClassDescriptor.java b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaClassDescriptor.java new file mode 100644 index 0000000000000000000000000000000000000000..57e319b3e57679b6ffb07acd70e56399411f75a6 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaClassDescriptor.java @@ -0,0 +1,94 @@ +package org.jetbrains.jet.lang.resolve.java; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.resolve.JetScope; +import org.jetbrains.jet.lang.resolve.SubstitutingScope; +import org.jetbrains.jet.lang.types.*; + +import java.util.List; +import java.util.Map; + +/** + * @author abreslav + */ +public class JavaClassDescriptor extends MutableDeclarationDescriptor implements ClassDescriptor { + + private TypeConstructor typeConstructor; + private JavaClassMembersScope unsubstitutedMemberScope; + private final WritableFunctionGroup constructors = new WritableFunctionGroup(""); + + public JavaClassDescriptor(DeclarationDescriptor containingDeclaration) { + super(containingDeclaration); + } + + public void setTypeConstructor(TypeConstructor typeConstructor) { + this.typeConstructor = typeConstructor; + } + + public void setUnsubstitutedMemberScope(JavaClassMembersScope memberScope) { + this.unsubstitutedMemberScope = memberScope; + } + + public void addConstructor(ConstructorDescriptor constructorDescriptor) { + this.constructors.addFunction(constructorDescriptor); + } + + private TypeSubstitutor createTypeSubstitutor(List typeArguments) { + List parameters = getTypeConstructor().getParameters(); + Map context = TypeUtils.buildSubstitutionContext(parameters, typeArguments); + return TypeSubstitutor.create(context); + } + + @NotNull + @Override + public JetScope getMemberScope(List typeArguments) { + assert typeArguments.size() == typeConstructor.getParameters().size(); + + if (typeArguments.isEmpty()) return unsubstitutedMemberScope; + + TypeSubstitutor substitutor = createTypeSubstitutor(typeArguments); + return new SubstitutingScope(unsubstitutedMemberScope, substitutor); + } + + @NotNull + @Override + public FunctionGroup getConstructors(List typeArguments) { + assert typeArguments.size() == typeConstructor.getParameters().size(); + if (typeArguments.isEmpty()) return constructors; + return new LazySubstitutingFunctionGroup(createTypeSubstitutor(typeArguments), constructors); + } + + @Override + public ConstructorDescriptor getUnsubstitutedPrimaryConstructor() { + return null; + } + + @Override + public boolean hasConstructors() { + return constructors.isEmpty(); + } + + @NotNull + @Override + public TypeConstructor getTypeConstructor() { + return typeConstructor; + } + + @NotNull + @Override + public JetType getDefaultType() { + return TypeUtils.makeUnsubstitutedType(this, unsubstitutedMemberScope); + } + + @NotNull + @Override + public ClassDescriptor substitute(TypeSubstitutor substitutor) { + throw new UnsupportedOperationException(); // TODO + } + + @Override + public R accept(DeclarationDescriptorVisitor visitor, D data) { + return visitor.visitClassDescriptor(this, data); + } +} diff --git a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java index 35fbb0e62812e56d70c63e33d269f60a3fea6a3a..7d8b18fb5fa4c664486ad8297614bec3567beabd 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -73,7 +73,7 @@ public class JavaDescriptorResolver { String name = psiClass.getName(); PsiModifierList modifierList = psiClass.getModifierList(); - MutableClassDescriptor classDescriptor = new MutableClassDescriptor( + JavaClassDescriptor classDescriptor = new JavaClassDescriptor( JAVA_ROOT ); classDescriptor.setName(name); diff --git a/idea/tests/org/jetbrains/jet/resolve/ExpectedResolveData.java b/idea/tests/org/jetbrains/jet/resolve/ExpectedResolveData.java index 8a08dbeb02d43205ec9bd80cb54ba20e35044959..bc3854e7ab5f21072231f7ff3e62ee0848214c7a 100644 --- a/idea/tests/org/jetbrains/jet/resolve/ExpectedResolveData.java +++ b/idea/tests/org/jetbrains/jet/resolve/ExpectedResolveData.java @@ -81,7 +81,7 @@ public class ExpectedResolveData { text = document.getText(); } -// System.out.println("text = " + text); + System.out.println("text = " + text); } public void checkResult(JetFile file) {