From d40bec3eba2ea6a0087719aa94633ec7ee47c75e Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Wed, 11 May 2011 18:26:53 +0400 Subject: [PATCH] JET-26 Check bounds in generic types: fixed substitution problems --- idea/src/jet/Library.jet | 23 ++-- .../jet/codegen/ExpressionCodegen.java | 6 +- .../jetbrains/jet/codegen/JetTypeMapper.java | 2 +- .../AbstractNamespaceDescriptorImpl.java | 38 +++++++ .../descriptors/MutableClassDescriptor.java | 24 ++++- .../lang/descriptors/NamespaceDescriptor.java | 43 +------- .../descriptors/NamespaceDescriptorImpl.java | 54 ++++++++++ .../jet/lang/descriptors/NamespaceLike.java | 8 +- .../jet/lang/resolve/AnalyzingUtils.java | 39 ++++++- .../lang/resolve/ClassDescriptorResolver.java | 39 ++++--- .../jet/lang/resolve/TopDownAnalyzer.java | 101 ++++++++++++------ .../jet/lang/resolve/TypeResolver.java | 23 ++-- .../jet/lang/resolve/WritableScopeImpl.java | 3 +- .../resolve/java/JavaDescriptorResolver.java | 8 +- .../resolve/java/JavaNamespaceDescriptor.java | 30 ++++++ .../jet/lang/types/DeferredType.java | 60 +++++++++++ .../jet/lang/types/JetStandardClasses.java | 3 +- .../jet/lang/types/JetStandardLibrary.java | 11 +- .../jet/lang/types/JetTypeInferrer.java | 16 ++- .../jetbrains/jet/lang/types/LazyValue.java | 47 ++++++++ ...enteringLazyValueComputationException.java | 21 ++++ idea/testData/checker/Bounds.jet | 17 +++ 22 files changed, 481 insertions(+), 135 deletions(-) create mode 100644 idea/src/org/jetbrains/jet/lang/descriptors/AbstractNamespaceDescriptorImpl.java create mode 100644 idea/src/org/jetbrains/jet/lang/descriptors/NamespaceDescriptorImpl.java create mode 100644 idea/src/org/jetbrains/jet/lang/resolve/java/JavaNamespaceDescriptor.java create mode 100644 idea/src/org/jetbrains/jet/lang/types/DeferredType.java create mode 100644 idea/src/org/jetbrains/jet/lang/types/LazyValue.java create mode 100644 idea/src/org/jetbrains/jet/lang/types/ReenteringLazyValueComputationException.java diff --git a/idea/src/jet/Library.jet b/idea/src/jet/Library.jet index aa7a2b95e66..429dc0fa0e0 100644 --- a/idea/src/jet/Library.jet +++ b/idea/src/jet/Library.jet @@ -7,7 +7,7 @@ class TypeInfo { class Iterator { fun next() : T - val hasNext : Boolean + abstract val hasNext : Boolean } class Iterable { @@ -38,7 +38,7 @@ class Boolean : Comparable { fun equals(other : Any?) : Boolean } -class String : Comparable { +class String() : Comparable { fun get(index : Int) : Char val length : Int @@ -50,19 +50,18 @@ class Range> { fun contains(item : T) : Boolean } -class IntRange : Range, Iterable { +class IntRange> : Range, Iterable { } class Number : Hashable { - val dbl : Double - val flt : Float - val lng : Long - val int : Int - val chr : Char - val sht : Short - val byt : Byte - + abstract val dbl : Double + abstract val flt : Float + abstract val lng : Long + abstract val int : Int + abstract val chr : Char + abstract val sht : Short + abstract val byt : Byte // fun equals(other : Double) : Boolean // fun equals(other : Float) : Boolean // fun equals(other : Long) : Boolean @@ -526,4 +525,4 @@ class Byte : Number, Comparable { fun dec() : Byte fun plus() : Int fun minus() : Int -} \ No newline at end of file +} diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 659052dcfd2..e6faecf1c8d 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -467,7 +467,7 @@ public class ExpressionCodegen extends JetVisitor { } } - boolean isStatic = descriptor.getContainingDeclaration() instanceof NamespaceDescriptor; + boolean isStatic = descriptor.getContainingDeclaration() instanceof NamespaceDescriptorImpl; final boolean directToField = expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER; final StackValue iValue = intermediateValueForProperty(propertyDescriptor, directToField); if (!isStatic) { @@ -482,7 +482,7 @@ public class ExpressionCodegen extends JetVisitor { } public StackValue intermediateValueForProperty(PropertyDescriptor propertyDescriptor, final boolean directToField) { - boolean isStatic = propertyDescriptor.getContainingDeclaration() instanceof NamespaceDescriptor; + boolean isStatic = propertyDescriptor.getContainingDeclaration() instanceof NamespaceDescriptorImpl; final JetType outType = propertyDescriptor.getOutType(); boolean isInsideClass = propertyDescriptor.getContainingDeclaration() == contextType; Method getter; @@ -572,7 +572,7 @@ public class ExpressionCodegen extends JetVisitor { } else { methodDescriptor = typeMapper.mapSignature((JetFunction) declarationPsiElement); - if (functionParent instanceof NamespaceDescriptor && declarationPsiElement instanceof JetFunction) { + if (functionParent instanceof NamespaceDescriptorImpl && declarationPsiElement instanceof JetFunction) { pushMethodArguments(expression, methodDescriptor); final String owner = NamespaceCodegen.getJVMClassName(DescriptorUtil.getFQName(functionParent)); v.invokestatic(owner, methodDescriptor.getName(), methodDescriptor.getDescriptor()); diff --git a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java index c7cb69c4c82..d2360dd8a5e 100644 --- a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -86,7 +86,7 @@ public class JetTypeMapper { static String getOwner(DeclarationDescriptor descriptor, OwnerKind kind) { String owner; - if (descriptor.getContainingDeclaration() instanceof NamespaceDescriptor) { + if (descriptor.getContainingDeclaration() instanceof NamespaceDescriptorImpl) { owner = jvmName((NamespaceDescriptor) descriptor.getContainingDeclaration()); } else if (descriptor.getContainingDeclaration() instanceof ClassDescriptor) { diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/AbstractNamespaceDescriptorImpl.java b/idea/src/org/jetbrains/jet/lang/descriptors/AbstractNamespaceDescriptorImpl.java new file mode 100644 index 00000000000..59ce7605373 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/descriptors/AbstractNamespaceDescriptorImpl.java @@ -0,0 +1,38 @@ +package org.jetbrains.jet.lang.descriptors; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.types.NamespaceType; +import org.jetbrains.jet.lang.types.TypeSubstitutor; + +import java.util.List; + +/** + * @author abreslav + */ +public abstract class AbstractNamespaceDescriptorImpl extends DeclarationDescriptorImpl implements NamespaceDescriptor { + private NamespaceType namespaceType; + + public AbstractNamespaceDescriptorImpl(DeclarationDescriptor containingDeclaration, List annotations, String name) { + super(containingDeclaration, annotations, name); + } + + @Override + @NotNull + public NamespaceType getNamespaceType() { + if (namespaceType == null) { + namespaceType = new NamespaceType(getName(), getMemberScope()); + } + return namespaceType; + } + + @NotNull + @Override + public NamespaceDescriptor substitute(TypeSubstitutor substitutor) { + throw new UnsupportedOperationException("This operation does not make sense for a namespace"); + } + + @Override + public R accept(DeclarationDescriptorVisitor visitor, D data) { + return visitor.visitNamespaceDescriptor(this, data); + } +} diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java b/idea/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java index 2892124cd4d..759c4878926 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java @@ -14,7 +14,7 @@ import java.util.Set; /** * @author abreslav */ -public class MutableClassDescriptor extends MutableDeclarationDescriptor implements ClassDescriptor { +public class MutableClassDescriptor extends MutableDeclarationDescriptor implements ClassDescriptor, NamespaceLike { private ConstructorDescriptor primaryConstructor; private final WritableFunctionGroup constructors = new WritableFunctionGroup(""); private final Set functions = Sets.newHashSet(); @@ -71,7 +71,8 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme constructors.addFunction(constructorDescriptor); } - public void addProperty(@NotNull PropertyDescriptor propertyDescriptor) { + @Override + public void addPropertyDescriptor(@NotNull PropertyDescriptor propertyDescriptor) { properties.add(propertyDescriptor); } @@ -80,7 +81,8 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme return properties; } - public void addFunction(@NotNull FunctionDescriptor functionDescriptor) { + @Override + public void addFunctionDescriptor(@NotNull FunctionDescriptor functionDescriptor) { functions.add(functionDescriptor); } @@ -89,6 +91,21 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme return functions; } + @Override + public NamespaceDescriptorImpl getNamespace(String name) { + throw new UnsupportedOperationException("Classes do not define namespaces"); + } + + @Override + public void addNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) { + throw new UnsupportedOperationException("Classes do not define namespaces"); + } + + @Override + public void addClassifierDescriptor(@NotNull MutableClassDescriptor classDescriptor) { + classes.add(classDescriptor); + } + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public void setUnsubstitutedMemberScope(@NotNull JetScope unsubstitutedMemberScope) { @@ -99,6 +116,7 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme @NotNull @Override public TypeConstructor getTypeConstructor() { + assert typeConstructor != null : "Type constructor is not set for " + getName(); return typeConstructor; } diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/NamespaceDescriptor.java b/idea/src/org/jetbrains/jet/lang/descriptors/NamespaceDescriptor.java index b56846a0d35..d54a5736b8e 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/NamespaceDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/NamespaceDescriptor.java @@ -1,51 +1,16 @@ package org.jetbrains.jet.lang.descriptors; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.resolve.JetScope; import org.jetbrains.jet.lang.types.NamespaceType; -import org.jetbrains.jet.lang.types.TypeSubstitutor; - -import java.util.List; /** * @author abreslav */ -public class NamespaceDescriptor extends DeclarationDescriptorImpl { - private NamespaceType namespaceType; - - private JetScope memberScope; - - public NamespaceDescriptor(@Nullable DeclarationDescriptor containingDeclaration, @NotNull List annotations, @NotNull String name) { - super(containingDeclaration, annotations, name); - } - - public void initialize(@NotNull JetScope memberScope) { - this.memberScope = memberScope; - } +public interface NamespaceDescriptor extends Annotated, Named, DeclarationDescriptor { + @NotNull + JetScope getMemberScope(); @NotNull - public JetScope getMemberScope() { - return memberScope; - } - - @NotNull - public NamespaceType getNamespaceType() { - if (namespaceType == null) { - assert memberScope != null : "Member scope not set"; - namespaceType = new NamespaceType(getName(), memberScope); - } - return namespaceType; - } - - @NotNull - @Override - public NamespaceDescriptor substitute(TypeSubstitutor substitutor) { - return this; - } - - @Override - public R accept(DeclarationDescriptorVisitor visitor, D data) { - return visitor.visitNamespaceDescriptor(this, data); - } + NamespaceType getNamespaceType(); } diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/NamespaceDescriptorImpl.java b/idea/src/org/jetbrains/jet/lang/descriptors/NamespaceDescriptorImpl.java new file mode 100644 index 00000000000..5ea4e4c24cc --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/descriptors/NamespaceDescriptorImpl.java @@ -0,0 +1,54 @@ +package org.jetbrains.jet.lang.descriptors; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.resolve.WritableScope; + +import java.util.List; + +/** + * @author abreslav + */ +public class NamespaceDescriptorImpl extends AbstractNamespaceDescriptorImpl implements NamespaceLike { + + private WritableScope memberScope; + + public NamespaceDescriptorImpl(@Nullable DeclarationDescriptor containingDeclaration, @NotNull List annotations, @NotNull String name) { + super(containingDeclaration, annotations, name); + } + + public void initialize(@NotNull WritableScope memberScope) { + this.memberScope = memberScope; + } + + @Override + @NotNull + public WritableScope getMemberScope() { + return memberScope; + } + + @Override + public NamespaceDescriptorImpl getNamespace(String name) { + return (NamespaceDescriptorImpl) memberScope.getDeclaredNamespace(name); + } + + @Override + public void addNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) { + memberScope.addNamespace(namespaceDescriptor); + } + + @Override + public void addClassifierDescriptor(@NotNull MutableClassDescriptor classDescriptor) { + memberScope.addClassifierDescriptor(classDescriptor); + } + + @Override + public void addFunctionDescriptor(@NotNull FunctionDescriptor functionDescriptor) { + memberScope.addFunctionDescriptor(functionDescriptor); + } + + @Override + public void addPropertyDescriptor(@NotNull PropertyDescriptor variableDescriptor) { + memberScope.addVariableDescriptor(variableDescriptor); + } +} diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/NamespaceLike.java b/idea/src/org/jetbrains/jet/lang/descriptors/NamespaceLike.java index f8d83fdd349..5fa2421a753 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/NamespaceLike.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/NamespaceLike.java @@ -58,9 +58,13 @@ public interface NamespaceLike extends DeclarationDescriptor { } @Nullable - NamespaceDescriptor getNamespace(String name); + NamespaceDescriptorImpl getNamespace(String name); void addNamespace(@NotNull NamespaceDescriptor namespaceDescriptor); - void addClassifierDescriptor(MutableClassDescriptor classDescriptor); + void addClassifierDescriptor(@NotNull MutableClassDescriptor classDescriptor); + + void addFunctionDescriptor(@NotNull FunctionDescriptor functionDescriptor); + + void addPropertyDescriptor(@NotNull PropertyDescriptor propertyDescriptor); } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java b/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java index 3a2804cdcd1..664121f8dc4 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java @@ -14,12 +14,15 @@ import org.jetbrains.jet.lang.ErrorHandler; import org.jetbrains.jet.lang.JetDiagnostic; import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; -import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.psi.JetDeclaration; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetNamespace; import org.jetbrains.jet.lang.resolve.java.JavaPackageScope; import org.jetbrains.jet.lang.resolve.java.JavaSemanticServices; +import java.util.Collections; + /** * @author abreslav */ @@ -51,13 +54,43 @@ public class AnalyzingUtils { JavaSemanticServices javaSemanticServices = new JavaSemanticServices(project, semanticServices, bindingTraceContext); JetScope libraryScope = semanticServices.getStandardLibrary().getLibraryScope(); - WritableScope scope = new WritableScopeImpl(libraryScope, new ModuleDescriptor(""), bindingTraceContext.getErrorHandler(), null); + ModuleDescriptor owner = new ModuleDescriptor(""); + final WritableScope scope = new WritableScopeImpl(libraryScope, owner, bindingTraceContext.getErrorHandler(), null); // scope.importScope(javaSemanticServices.getDescriptorResolver().resolveNamespace("").getMemberScope()); // scope.importScope(javaSemanticServices.getDescriptorResolver().resolveNamespace("java.lang").getMemberScope()); scope.importScope(new JavaPackageScope("", null, javaSemanticServices)); scope.importScope(new JavaPackageScope("java.lang", null, javaSemanticServices)); - new TopDownAnalyzer(semanticServices, bindingTraceContext, flowDataTraceFactory).process(scope, namespace); + TopDownAnalyzer topDownAnalyzer = new TopDownAnalyzer(semanticServices, bindingTraceContext, flowDataTraceFactory); +// topDownAnalyzer.process(scope, Collections.singletonList(namespace)); +// if (false) + topDownAnalyzer.process(scope, new NamespaceLike.Adapter(owner) { + + @Override + public NamespaceDescriptorImpl getNamespace(String name) { + return null; + } + + @Override + public void addNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) { + scope.addNamespace(namespaceDescriptor); + } + + @Override + public void addClassifierDescriptor(@NotNull MutableClassDescriptor classDescriptor) { + scope.addClassifierDescriptor(classDescriptor); + } + + @Override + public void addFunctionDescriptor(@NotNull FunctionDescriptor functionDescriptor) { + scope.addFunctionDescriptor(functionDescriptor); + } + + @Override + public void addPropertyDescriptor(@NotNull PropertyDescriptor propertyDescriptor) { + scope.addVariableDescriptor(propertyDescriptor); + } + }, Collections.singletonList(namespace)); return bindingTraceContext; } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java index 8bba26ff21b..d8a19259147 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java @@ -54,7 +54,7 @@ public class ClassDescriptorResolver { // TODO : assuming that the hierarchy is acyclic Collection supertypes = delegationSpecifiers.isEmpty() ? Collections.singleton(JetStandardClasses.getAnyType()) - : resolveDelegationSpecifiers(parameterScope, delegationSpecifiers); + : resolveDelegationSpecifiers(parameterScope, delegationSpecifiers, typeResolver); boolean open = classElement.hasModifier(JetTokens.OPEN_KEYWORD); WritableScope members = resolveMembers(classDescriptor, classElement, typeParameters, scope, parameterScope, supertypes); @@ -124,6 +124,9 @@ public class ClassDescriptorResolver { if (extendsBound != null) { typeParameterDescriptor.addUpperBound(typeResolverNotCheckingBounds.resolveType(classDescriptor.getClassHeaderScope(), extendsBound)); } + else { + typeParameterDescriptor.addUpperBound(JetStandardClasses.getDefaultBound()); + } } // TODO : Bounds from with } @@ -133,7 +136,7 @@ public class ClassDescriptorResolver { // TODO : assuming that the hierarchy is acyclic Collection superclasses = delegationSpecifiers.isEmpty() ? Collections.singleton(JetStandardClasses.getAnyType()) - : resolveDelegationSpecifiers(descriptor.getClassHeaderScope(), delegationSpecifiers); + : resolveDelegationSpecifiers(descriptor.getClassHeaderScope(), delegationSpecifiers, typeResolverNotCheckingBounds); ((TypeConstructorImpl) descriptor.getTypeConstructor()).getSupertypes().addAll(superclasses); } @@ -164,7 +167,7 @@ public class ClassDescriptorResolver { // TODO : assuming that the hierarchy is acyclic Collection superclasses = delegationSpecifiers.isEmpty() ? Collections.singleton(JetStandardClasses.getAnyType()) - : resolveDelegationSpecifiers(parameterScope, delegationSpecifiers); + : resolveDelegationSpecifiers(parameterScope, delegationSpecifiers, typeResolver); // TODO : UGLY HACK supertypes.addAll(superclasses); @@ -325,7 +328,7 @@ public class ClassDescriptorResolver { return typeParameterDescriptor; } - private Collection resolveDelegationSpecifiers(WritableScope extensibleScope, List delegationSpecifiers) { + private Collection resolveDelegationSpecifiers(WritableScope extensibleScope, List delegationSpecifiers, @NotNull TypeResolver resolver) { if (delegationSpecifiers.isEmpty()) { return Collections.emptyList(); } @@ -333,7 +336,7 @@ public class ClassDescriptorResolver { for (JetDelegationSpecifier delegationSpecifier : delegationSpecifiers) { JetTypeReference typeReference = delegationSpecifier.getTypeReference(); if (typeReference != null) { - result.add(typeResolver.resolveType(extensibleScope, typeReference)); + result.add(resolver.resolveType(extensibleScope, typeReference)); } else { result.add(ErrorUtils.createErrorType("No type reference")); @@ -489,19 +492,25 @@ public class ClassDescriptorResolver { } @NotNull - private JetType getType(@NotNull JetScope scope, @NotNull JetProperty property) { + private JetType getType(@NotNull final JetScope scope, @NotNull JetProperty property) { // TODO : receiver? JetTypeReference propertyTypeRef = property.getPropertyTypeRef(); JetType type; if (propertyTypeRef == null) { - JetExpression initializer = property.getInitializer(); + final JetExpression initializer = property.getInitializer(); if (initializer == null) { trace.getErrorHandler().genericError(property.getNode(), "This property must either have a type annotation or be initialized"); type = ErrorUtils.createErrorType("No type, no body"); } else { // TODO : ??? Fix-point here: what if we have something like "val a = foo {a.bar()}" - type = semanticServices.getTypeInferrer(trace, JetFlowInformationProvider.THROW_EXCEPTION).safeGetType(scope, initializer, false); + // TODO : a risk of a memory leak + type = new DeferredType(new LazyValue() { + @Override + protected JetType compute() { + return semanticServices.getTypeInferrer(trace, JetFlowInformationProvider.THROW_EXCEPTION).safeGetType(scope, initializer, false); + } + }); } } else { type = typeResolver.resolveType(scope, propertyTypeRef); @@ -590,6 +599,7 @@ public class ClassDescriptorResolver { List typeReferences = typeElement.getTypeArgumentsAsTypes(); assert typeReferences.size() == arguments.size() : typeElement.getText(); + TypeSubstitutor substitutor = TypeSubstitutor.create(type); for (int i = 0, projectionsSize = typeReferences.size(); i < projectionsSize; i++) { JetTypeReference argumentTypeReference = typeReferences.get(i); @@ -599,14 +609,19 @@ public class ClassDescriptorResolver { checkBounds(argumentTypeReference, typeArgument); TypeParameterDescriptor typeParameterDescriptor = parameters.get(i); - checkBounds(argumentTypeReference, typeArgument, typeParameterDescriptor); + checkBounds(argumentTypeReference, typeArgument, typeParameterDescriptor, substitutor); } } - public void checkBounds(@NotNull JetTypeReference argumentTypeReference, @NotNull JetType typeArgument, @NotNull TypeParameterDescriptor typeParameterDescriptor) { + public void checkBounds( + @NotNull JetTypeReference argumentTypeReference, + @NotNull JetType typeArgument, + @NotNull TypeParameterDescriptor typeParameterDescriptor, + @NotNull TypeSubstitutor substitutor) { for (JetType bound : typeParameterDescriptor.getUpperBounds()) { - if (!semanticServices.getTypeChecker().isSubtypeOf(typeArgument, bound)) { - trace.getErrorHandler().genericError(argumentTypeReference.getNode(), "An upper bound " + bound + " is violated"); // TODO : Message + JetType substitutedBound = substitutor.safeSubstitute(bound, Variance.INVARIANT); + if (!semanticServices.getTypeChecker().isSubtypeOf(typeArgument, substitutedBound)) { + trace.getErrorHandler().genericError(argumentTypeReference.getNode(), "An upper bound " + substitutedBound + " is violated"); // TODO : Message } } } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index c118c8cb0a1..ddeaf1b6a4d 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -25,8 +25,10 @@ import java.util.*; public class TopDownAnalyzer { private final Map classes = Maps.newLinkedHashMap(); - private final Map namespaceScopes = new LinkedHashMap(); - private final Map functions = Maps.newLinkedHashMap(); + private final Map namespaceScopes = Maps.newHashMap(); + private final Map namespaceDescriptors = Maps.newHashMap(); + + private final Map functions = Maps.newLinkedHashMap(); private final Map constructors = Maps.newLinkedHashMap(); private final Map properties = new LinkedHashMap(); private final Map declaringScopes = Maps.newHashMap(); @@ -82,19 +84,24 @@ public class TopDownAnalyzer { this(semanticServices, bindingTrace, JetControlFlowDataTraceFactory.EMPTY); } - public void process(@NotNull JetScope outerScope, @NotNull JetDeclaration declaration) { - process(outerScope, Collections.singletonList(declaration)); - } +// public void process(@NotNull JetScope outerScope, @NotNull JetDeclaration declaration) { +// process(outerScope, Collections.singletonList(declaration)); +// } - public void process(@NotNull WritableScope outerScope, T owner, @NotNull List declarations) { + public void process(@NotNull WritableScope 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) checkGenericBoundsInClassHeaders(); // For the types resolved so far - resolveFunctionAndPropertyHeaders(); // TODO : for now, fail fast if something is unknown yet (i.e. some type annotation is omitted) + resolveFunctionAndPropertyHeaders(declarations); // TODO : for now, fail fast if something is unknown yet (i.e. some type annotation is omitted) resolveExecutableCode(); +// processBehaviorDeclarators(outerScope, declarations); + +// readyToProcessExpressions = true; +// resolveBehaviorDeclarationBodies(); + } private void collectNamespacesAndClassifiers( @@ -111,10 +118,10 @@ public class TopDownAnalyzer { if (name == null) { name = ""; } - NamespaceDescriptor namespaceDescriptor = owner.getNamespace(name); + NamespaceDescriptorImpl namespaceDescriptor = owner.getNamespace(name); if (namespaceDescriptor == null) { - namespaceDescriptor = new NamespaceDescriptor( - owner, //declaringScope.getContainingDeclaration(), + namespaceDescriptor = new NamespaceDescriptorImpl( + owner.getOriginal(), //declaringScope.getContainingDeclaration(), Collections.emptyList(), // TODO name ); @@ -122,8 +129,9 @@ public class TopDownAnalyzer { owner.addNamespace(namespaceDescriptor); trace.recordDeclarationResolution(namespace, namespaceDescriptor); } + namespaceDescriptors.put(namespace, namespaceDescriptor); - WritableScope namespaceScope = new WritableScopeImpl(outerScope, owner, trace.getErrorHandler(), null); + WritableScope namespaceScope = new WriteThroughScope(outerScope, (WritableScope) namespaceDescriptor.getMemberScope()); namespaceScopes.put(namespace, namespaceScope); for (JetImportDirective importDirective : importDirectives) { @@ -143,23 +151,7 @@ public class TopDownAnalyzer { } } - final NamespaceDescriptor finalNamespaceDescriptor = namespaceDescriptor; - collectNamespacesAndClassifiers(namespaceScope, new NamespaceLike.Adapter(finalNamespaceDescriptor) { - @Override - public NamespaceDescriptor getNamespace(String name) { - return ((WritableScope) finalNamespaceDescriptor.getMemberScope()).getDeclaredNamespace(name); - } - - @Override - public void addNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) { - ((WritableScope) namespaceDescriptor.getMemberScope()).addNamespace(namespaceDescriptor); - } - - @Override - public void addClassifierDescriptor(MutableClassDescriptor classDescriptor) { - ((WritableScope) finalNamespaceDescriptor.getMemberScope()).addClassifierDescriptor(classDescriptor); - } - }, namespace.getDeclarations()); + collectNamespacesAndClassifiers(namespaceScope, namespaceDescriptor, namespace.getDeclarations()); } @Override @@ -228,12 +220,53 @@ public class TopDownAnalyzer { } - private void resolveFunctionAndPropertyHeaders() { - throw new UnsupportedOperationException(); // TODO + private void resolveFunctionAndPropertyHeaders(@NotNull List declarations) { + for (Map.Entry entry : namespaceScopes.entrySet()) { + JetNamespace namespace = entry.getKey(); + final WritableScope namespaceScope = entry.getValue(); + final NamespaceLike namespaceDescriptor = namespaceDescriptors.get(namespace); + + resolveFunctionAndPropertyHeaders(namespace.getDeclarations(), namespaceScope, namespaceDescriptor); + } + for (Map.Entry entry : classes.entrySet()) { + JetClass jetClass = entry.getKey(); + final MutableClassDescriptor classDescriptor = entry.getValue(); + + resolveFunctionAndPropertyHeaders(jetClass.getDeclarations(), classDescriptor.getClassHeaderScope(), classDescriptor); + processPrimaryConstructor(classDescriptor, jetClass); +// processBehaviorDeclarators(classDescriptor.getWritableUnsubstitutedMemberScope(), jetClass.getDeclarations()); + + // TODO : Constructors + } + + // TODO : Extensions + } + + private void resolveFunctionAndPropertyHeaders(@NotNull List declarations, final @NotNull JetScope scope, final @NotNull NamespaceLike namespaceLike) { + for (JetDeclaration declaration : declarations) { + declaration.accept(new JetVisitor() { + @Override + public void visitFunction(JetFunction 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); + } + }); + } } private void resolveExecutableCode() { - throw new UnsupportedOperationException(); // TODO + readyToProcessExpressions = true; + resolveBehaviorDeclarationBodies(); } @NotNull @@ -263,9 +296,9 @@ public class TopDownAnalyzer { if (name == null) { name = ""; } - NamespaceDescriptor namespaceDescriptor = declaringScope.getDeclaredNamespace(name); + NamespaceDescriptorImpl namespaceDescriptor = (NamespaceDescriptorImpl) declaringScope.getDeclaredNamespace(name); if (namespaceDescriptor == null) { - namespaceDescriptor = new NamespaceDescriptor( + namespaceDescriptor = new NamespaceDescriptorImpl( declaringScope.getContainingDeclaration(), Collections.emptyList(), // TODO name @@ -814,7 +847,7 @@ public class TopDownAnalyzer { } private void resolveFunctionBodies() { - for (Map.Entry entry : functions.entrySet()) { + for (Map.Entry entry : functions.entrySet()) { JetDeclaration declaration = entry.getKey(); FunctionDescriptor descriptor = entry.getValue(); diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TypeResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/TypeResolver.java index 6905fa952ae..31f89981314 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/TypeResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/TypeResolver.java @@ -92,17 +92,6 @@ public class TypeResolver { trace.getErrorHandler().genericError(type.getTypeArgumentList().getNode(), errorMessage); } } else { - if (checkBounds) { - for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) { - TypeParameterDescriptor parameter = parameters.get(i); - JetType argument = arguments.get(i).getType(); - JetTypeReference typeReference = type.getTypeArguments().get(i).getTypeReference(); - - if (typeReference != null) { - semanticServices.getClassDescriptorResolver(trace).checkBounds(typeReference, argument, parameter); - } - } - } result[0] = new JetTypeImpl( annotations, typeConstructor, @@ -110,6 +99,18 @@ public class TypeResolver { arguments, classDescriptor.getMemberScope(arguments) ); + if (checkBounds) { + TypeSubstitutor substitutor = TypeSubstitutor.create(result[0]); + for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) { + TypeParameterDescriptor parameter = parameters.get(i); + JetType argument = arguments.get(i).getType(); + JetTypeReference typeReference = type.getTypeArguments().get(i).getTypeReference(); + + if (typeReference != null) { + semanticServices.getClassDescriptorResolver(trace).checkBounds(typeReference, argument, parameter, substitutor); + } + } + } } } } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/WritableScopeImpl.java b/idea/src/org/jetbrains/jet/lang/resolve/WritableScopeImpl.java index d0052763a8b..68a68417bd0 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/WritableScopeImpl.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/WritableScopeImpl.java @@ -1,5 +1,6 @@ package org.jetbrains.jet.lang.resolve; +import com.google.common.collect.Maps; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.ErrorHandler; @@ -244,7 +245,7 @@ public class WritableScopeImpl extends WritableScopeWithImports { @NotNull public Map getNamespaceDescriptors() { if (namespaceDescriptors == null) { - namespaceDescriptors = new HashMap(); + namespaceDescriptors = Maps.newHashMap(); } return namespaceDescriptors; } 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 0e3f4838546..35fbb0e6281 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -189,23 +189,23 @@ public class JavaDescriptorResolver { } private NamespaceDescriptor createJavaNamespaceDescriptor(PsiPackage psiPackage) { - NamespaceDescriptor namespaceDescriptor = new NamespaceDescriptor( + JavaNamespaceDescriptor namespaceDescriptor = new JavaNamespaceDescriptor( JAVA_ROOT, Collections.emptyList(), // TODO psiPackage.getName() ); - namespaceDescriptor.initialize(new JavaPackageScope(psiPackage.getQualifiedName(), namespaceDescriptor, semanticServices)); + namespaceDescriptor.setMemberScope(new JavaPackageScope(psiPackage.getQualifiedName(), namespaceDescriptor, semanticServices)); semanticServices.getTrace().recordDeclarationResolution(psiPackage, namespaceDescriptor); return namespaceDescriptor; } private NamespaceDescriptor createJavaNamespaceDescriptor(@NotNull final PsiClass psiClass) { - NamespaceDescriptor namespaceDescriptor = new NamespaceDescriptor( + JavaNamespaceDescriptor namespaceDescriptor = new JavaNamespaceDescriptor( JAVA_ROOT, Collections.emptyList(), // TODO psiClass.getName() ); - namespaceDescriptor.initialize(new JavaClassMembersScope(namespaceDescriptor, psiClass, semanticServices, true)); + namespaceDescriptor.setMemberScope(new JavaClassMembersScope(namespaceDescriptor, psiClass, semanticServices, true)); semanticServices.getTrace().recordDeclarationResolution(psiClass, namespaceDescriptor); return namespaceDescriptor; } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaNamespaceDescriptor.java b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaNamespaceDescriptor.java new file mode 100644 index 00000000000..faea1f032ab --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaNamespaceDescriptor.java @@ -0,0 +1,30 @@ +package org.jetbrains.jet.lang.resolve.java; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.AbstractNamespaceDescriptorImpl; +import org.jetbrains.jet.lang.descriptors.Annotation; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.resolve.JetScope; + +import java.util.List; + +/** + * @author abreslav + */ +public class JavaNamespaceDescriptor extends AbstractNamespaceDescriptorImpl { + private JetScope memberScope; + + public JavaNamespaceDescriptor(DeclarationDescriptor containingDeclaration, List annotations, String name) { + super(containingDeclaration, annotations, name); + } + + public void setMemberScope(@NotNull JetScope memberScope) { + this.memberScope = memberScope; + } + + @NotNull + @Override + public JetScope getMemberScope() { + return memberScope; + } +} diff --git a/idea/src/org/jetbrains/jet/lang/types/DeferredType.java b/idea/src/org/jetbrains/jet/lang/types/DeferredType.java new file mode 100644 index 00000000000..b3fdc929e31 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/DeferredType.java @@ -0,0 +1,60 @@ +package org.jetbrains.jet.lang.types; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.Annotation; +import org.jetbrains.jet.lang.resolve.JetScope; + +import java.util.List; + +/** + * @author abreslav + */ +public class DeferredType implements JetType { + private final LazyValue lazyValue; + + public DeferredType(LazyValue lazyValue) { + this.lazyValue = lazyValue; + } + + public JetType getActualType() { + return lazyValue.get(); + } + + @Override + @NotNull + public JetScope getMemberScope() { + return getActualType().getMemberScope(); + } + + @Override + @NotNull + public TypeConstructor getConstructor() { + return getActualType().getConstructor(); + } + + @Override + @NotNull + public List getArguments() { + return getActualType().getArguments(); + } + + @Override + public boolean isNullable() { + return getActualType().isNullable(); + } + + @Override + public List getAnnotations() { + return getActualType().getAnnotations(); + } + + @Override + public String toString() { + try { + return getActualType().toString(); + } + catch (ReenteringLazyValueComputationException e) { + return ""; + } + } +} diff --git a/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java b/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java index 7e9bcff771e..5e94c1ac71f 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java @@ -22,7 +22,7 @@ public class JetStandardClasses { //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - private static NamespaceDescriptor STANDARD_CLASSES_NAMESPACE = new NamespaceDescriptor(null, Collections.emptyList(), "jet"); + /*package*/ static NamespaceDescriptorImpl STANDARD_CLASSES_NAMESPACE = new NamespaceDescriptorImpl(null, Collections.emptyList(), "jet"); private static final ClassDescriptor NOTHING_CLASS = new ClassDescriptorImpl( STANDARD_CLASSES_NAMESPACE, @@ -201,6 +201,7 @@ public class JetStandardClasses { } } } + STANDARD_CLASSES_NAMESPACE.initialize(writableScope); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/idea/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java b/idea/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java index 2cff5d852e2..e6923bce06b 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java @@ -4,14 +4,13 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.io.FileUtil; import com.intellij.psi.PsiFileFactory; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.ErrorHandler; import org.jetbrains.jet.lang.JetFileType; import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.descriptors.Annotation; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.psi.JetFile; -import org.jetbrains.jet.lang.resolve.BindingTraceContext; -import org.jetbrains.jet.lang.resolve.JetScope; -import org.jetbrains.jet.lang.resolve.TopDownAnalyzer; +import org.jetbrains.jet.lang.resolve.*; import java.io.IOException; import java.io.InputStream; @@ -73,7 +72,11 @@ public class JetStandardLibrary { JetSemanticServices bootstrappingSemanticServices = JetSemanticServices.createSemanticServices(this); BindingTraceContext bindingTraceContext = new BindingTraceContext(); TopDownAnalyzer bootstrappingTDA = new TopDownAnalyzer(bootstrappingSemanticServices, bindingTraceContext); - this.libraryScope = bootstrappingTDA.process(JetStandardClasses.STANDARD_CLASSES, file.getRootNamespace().getDeclarations()); + WritableScopeImpl writableScope = new WritableScopeImpl(JetStandardClasses.STANDARD_CLASSES, JetStandardClasses.STANDARD_CLASSES_NAMESPACE, ErrorHandler.THROW_EXCEPTION, null); +// this.libraryScope = bootstrappingTDA.process(JetStandardClasses.STANDARD_CLASSES, file.getRootNamespace().getDeclarations()); + bootstrappingTDA.process(writableScope, JetStandardClasses.STANDARD_CLASSES_NAMESPACE, file.getRootNamespace().getDeclarations()); + this.libraryScope = JetStandardClasses.STANDARD_CLASSES_NAMESPACE.getMemberScope(); + AnalyzingUtils.applyHandler(ErrorHandler.THROW_EXCEPTION, bindingTraceContext); this.byteClass = (ClassDescriptor) libraryScope.getClassifier("Byte"); this.charClass = (ClassDescriptor) libraryScope.getClassifier("Char"); diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index b9cf1d46d9d..1b98abd5f53 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -594,13 +594,19 @@ public class JetTypeInferrer { @Nullable public JetType getType(@NotNull JetExpression expression) { assert result == null; - expression.accept(this); - if (result != null) { - trace.recordExpressionType(expression, result); - if (JetStandardClasses.isNothing(result) && !result.isNullable()) { - markDominatedExpressionsAsUnreachable(expression); + try { + expression.accept(this); + if (result != null) { + trace.recordExpressionType(expression, result); + if (JetStandardClasses.isNothing(result) && !result.isNullable()) { + markDominatedExpressionsAsUnreachable(expression); + } } } + catch (ReenteringLazyValueComputationException e) { + trace.getErrorHandler().genericError(expression.getNode(), "Type inference has run into a recursive problem"); // TODO : message + result = null; + } return result; } diff --git a/idea/src/org/jetbrains/jet/lang/types/LazyValue.java b/idea/src/org/jetbrains/jet/lang/types/LazyValue.java new file mode 100644 index 00000000000..c40b4420bae --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/LazyValue.java @@ -0,0 +1,47 @@ +package org.jetbrains.jet.lang.types; + +import org.jetbrains.annotations.NotNull; + +/** + * @author abreslav + */ +public abstract class LazyValue { + + private enum State { + NOT_COMPUTED, + BEING_COMPUTED, + COMPUTED, + ERROR + } + + private State state = State.NOT_COMPUTED; + private T value; + + protected abstract T compute(); + + public State getState() { + return state; + } + + @NotNull + public final T get() { + switch (state) { + case NOT_COMPUTED: + state = State.BEING_COMPUTED; + value = compute(); + state = State.COMPUTED; + return value; + case BEING_COMPUTED: + state = State.ERROR; + throw new ReenteringLazyValueComputationException(); + case COMPUTED: + return value; + case ERROR: + throw new ReenteringLazyValueComputationException(); + } + throw new IllegalStateException("Unreachable"); + } + + + +} diff --git a/idea/src/org/jetbrains/jet/lang/types/ReenteringLazyValueComputationException.java b/idea/src/org/jetbrains/jet/lang/types/ReenteringLazyValueComputationException.java new file mode 100644 index 00000000000..36847c3ea4c --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/ReenteringLazyValueComputationException.java @@ -0,0 +1,21 @@ +package org.jetbrains.jet.lang.types; + +/** + * @author abreslav + */ +public class ReenteringLazyValueComputationException extends RuntimeException { + public ReenteringLazyValueComputationException() { + } + + public ReenteringLazyValueComputationException(String message) { + super(message); + } + + public ReenteringLazyValueComputationException(String message, Throwable cause) { + super(message, cause); + } + + public ReenteringLazyValueComputationException(Throwable cause) { + super(cause); + } +} diff --git a/idea/testData/checker/Bounds.jet b/idea/testData/checker/Bounds.jet index 890759ed260..fb3572843ec 100644 --- a/idea/testData/checker/Bounds.jet +++ b/idea/testData/checker/Bounds.jet @@ -1,3 +1,20 @@ +namespace boundsWithSubstitutors { + class A + class B>() + + class C : A + + val a = new B() + val a1 = new B<Int>() + + class X() + + val b = new X, C>> + val b0 = new XAny?> + val b1 = new X, String>> + +} + class A class B()