diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 40c242ab634..01a1d76eaed 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1813,23 +1813,25 @@ public class ExpressionCodegen extends JetVisitor { JetType jetType = bindingContext.get(BindingContext.TYPE, typeReference); assert jetType != null; DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor(); - if (!(descriptor instanceof ClassDescriptor)) { - throw new UnsupportedOperationException("don't know how to handle non-class types in as/as?"); - } - Type type = JetTypeMapper.boxType(typeMapper.mapType(jetType)); - generateInstanceOf(StackValue.expression(OBJECT_TYPE, expression.getLeft(), this), jetType, true); - Label isInstance = new Label(); - v.ifne(isInstance); - v.pop(); - if (opToken == JetTokens.AS_SAFE) { - v.aconst(null); + if (descriptor instanceof ClassDescriptor || descriptor instanceof TypeParameterDescriptor) { + Type type = JetTypeMapper.boxType(typeMapper.mapType(jetType)); + generateInstanceOf(StackValue.expression(OBJECT_TYPE, expression.getLeft(), this), jetType, true); + Label isInstance = new Label(); + v.ifne(isInstance); + v.pop(); + if (opToken == JetTokens.AS_SAFE) { + v.aconst(null); + } + else { + throwNewException(CLASS_TYPE_CAST_EXCEPTION); + } + v.mark(isInstance); + v.checkcast(type); + return StackValue.onStack(type); } else { - throwNewException(CLASS_TYPE_CAST_EXCEPTION); + throw new UnsupportedOperationException("don't know how to handle non-class types in as/as?"); } - v.mark(isInstance); - v.checkcast(type); - return StackValue.onStack(type); } } @@ -1962,7 +1964,7 @@ public class ExpressionCodegen extends JetVisitor { } } - private void generateTypeInfo(JetType jetType) { + void generateTypeInfo(JetType jetType) { String knownTypeInfo = typeMapper.isKnownTypeInfo(jetType); if(knownTypeInfo != null) { v.getstatic("jet/typeinfo/TypeInfo", knownTypeInfo, "Ljet/typeinfo/TypeInfo;"); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index e9f872046a6..aead6e36f70 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -9,6 +9,7 @@ import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.types.JetStandardClasses; import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.TypeProjection; import org.jetbrains.jet.lang.types.Variance; import org.jetbrains.jet.lexer.JetTokens; import org.objectweb.asm.ClassVisitor; @@ -109,7 +110,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { protected void getSuperClass() { List delegationSpecifiers = myClass.getDelegationSpecifiers(); - if(myClass instanceof JetClass && ((JetClass)myClass).isTrait()) + if(myClass instanceof JetClass && ((JetClass) myClass).isTrait()) return; for (JetDelegationSpecifier specifier : delegationSpecifiers) { @@ -150,6 +151,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } generateGetTypeInfo(); + //genGetSuperTypesTypeInfo(); } private void generateFieldForTypeInfo() { @@ -240,6 +242,10 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { final InstructionAdapter iv = new InstructionAdapter(mv); ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, context, state); + for(int slot = 0; slot != frameMap.getTypeParameterCount(); ++slot) { + codegen.addTypeParameter(constructorDescriptor.getTypeParameters().get(slot), StackValue.local(frameMap.getFirstTypeParameter() + slot, JetTypeMapper.TYPE_TYPEINFO)); + } + String classname = state.getTypeMapper().jvmName(descriptor, kind); final Type classType = Type.getType("L" + classname + ";"); @@ -348,7 +354,15 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { reg += argType.getSize(); } - String fdescriptor = function.getDescriptor().replace("(","(L" + state.getTypeMapper().jvmName((ClassDescriptor) fun.getContainingDeclaration(),OwnerKind.IMPLEMENTATION) + ";"); + ClassDescriptor containingDeclaration = (ClassDescriptor) fun.getContainingDeclaration(); + JetType jetType = TraitImplBodyCodegen.getSuperClass(containingDeclaration, state.getBindingContext()); + Type type = state.getTypeMapper().mapType(jetType); + if(type.getInternalName().equals("java/lang/Object")) { + jetType = containingDeclaration.getDefaultType(); + type = state.getTypeMapper().mapType(jetType); + } + + String fdescriptor = function.getDescriptor().replace("(","(" + type.getDescriptor()); iv.invokestatic(state.getTypeMapper().jvmName((ClassDescriptor) fun.getContainingDeclaration(), OwnerKind.TRAIT_IMPL), function.getName(), fdescriptor); iv.areturn(function.getReturnType()); mv.visitMaxs(0, 0); @@ -530,7 +544,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { iv.dup(); iv.iconst(i); iv.load(firstTypeParameter + i, JetTypeMapper.TYPE_OBJECT); - ExpressionCodegen.genTypeInfoToProjection(iv, Variance.INVARIANT); + iv.checkcast(JetTypeMapper.TYPE_TYPEINFOPROJECTION); iv.astore(JetTypeMapper.TYPE_OBJECT); } iv.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z[Ljet/typeinfo/TypeInfoProjection;)Ljet/typeinfo/TypeInfo;"); @@ -648,4 +662,50 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { private void generateClassObject(JetClassObject declaration) { state.forClass().generate(context, declaration.getObjectDeclaration()); } + + private void genGetSuperTypesTypeInfo() { + if(!(myClass instanceof JetClass) || ((JetClass)myClass).isTrait()) { + return; + } + + String sig = getGetSuperTypesTypeInfoSignature(descriptor.getDefaultType()); + + final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC|Opcodes.ACC_STATIC, + "$$getSuperTypesTypeInfo", + sig, + null /* TODO */, + null); + mv.visitCode(); + InstructionAdapter v = new InstructionAdapter(mv); + + ExpressionCodegen codegen = new ExpressionCodegen(v, new FrameMap(), Type.VOID_TYPE, context, state); + + v.load(0, JetTypeMapper.TYPE_OBJECT); + + int k = 1; + for (TypeParameterDescriptor parameterDescriptor : descriptor.getTypeConstructor().getParameters()) { + codegen.addTypeParameter(parameterDescriptor, StackValue.local(k++, JetTypeMapper.TYPE_TYPEINFO)); + } + + for(JetType superType : descriptor.getTypeConstructor().getSupertypes()) { + for (TypeProjection typeProjection : superType.getArguments()) { + codegen.generateTypeInfo(typeProjection.getType()); + } + v.invokestatic(state.getTypeMapper().mapType(superType).getInternalName(), "$$getSuperTypesTypeInfo", getGetSuperTypesTypeInfoSignature(superType)); + } + + v.areturn(Type.VOID_TYPE); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + + private static String getGetSuperTypesTypeInfoSignature(JetType type) { + List typeParameters = type.getConstructor().getParameters(); + StringBuilder sb = new StringBuilder("(Ljava/util/Set;"); + for(TypeParameterDescriptor tp : typeParameters) + sb.append("Ljet/typeinfo/TypeInfo;"); + sb.append(")V"); + + return sb.toString(); + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 5896a36e70b..e014f057e38 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -439,8 +439,13 @@ public class JetTypeMapper { } FunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, f); if(kind == OwnerKind.TRAIT_IMPL) { - JetType jetType = ((ClassDescriptor)functionDescriptor.getContainingDeclaration()).getDefaultType(); - final Type type = mapType(jetType); + ClassDescriptor containingDeclaration = (ClassDescriptor) functionDescriptor.getContainingDeclaration(); + JetType jetType = TraitImplBodyCodegen.getSuperClass(containingDeclaration, bindingContext); + Type type = mapType(jetType); + if(type.getInternalName().equals("java/lang/Object")) { + jetType = containingDeclaration.getDefaultType(); + type = mapType(jetType); + } valueParameterTypes.add(type); parameterTypes.add(type); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java index 8c87865c55b..ecf1b2c8ff7 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java @@ -1,9 +1,11 @@ package org.jetbrains.jet.codegen; -import org.jetbrains.jet.lang.psi.JetClass; -import org.jetbrains.jet.lang.psi.JetClassOrObject; -import org.jetbrains.jet.lang.psi.JetDeclaration; -import org.jetbrains.jet.lang.psi.JetNamedFunction; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lexer.JetTokens; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.Opcodes; @@ -16,6 +18,33 @@ public class TraitImplBodyCodegen extends ClassBodyCodegen { super(aClass, context, v, state); } + //todo not needed when frontend will be able to calculate properly + static JetType getSuperClass(ClassDescriptor myClassDescr, BindingContext bindingContext) { + JetClassOrObject myClass = (JetClassOrObject) bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, myClassDescr); + List delegationSpecifiers = myClass.getDelegationSpecifiers(); + + for (JetDelegationSpecifier specifier : delegationSpecifiers) { + if (specifier instanceof JetDelegatorToSuperClass || specifier instanceof JetDelegatorToSuperCall) { + JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference()); + ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); + final PsiElement declaration = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, superClassDescriptor); + if (declaration != null) { + if (declaration instanceof PsiClass) { + if (!((PsiClass) declaration).isInterface()) { + return superClassDescriptor.getDefaultType(); + } + } + else if(declaration instanceof JetClass) { + if(!((JetClass) declaration).isTrait()) { + return superClassDescriptor.getDefaultType(); + } + } + } + } + } + return null; + } + @Override protected void generateDeclaration() { v.visit(Opcodes.V1_6, diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionGroup.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionGroup.java index d767bce0cd9..1dcfc99cf83 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionGroup.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionGroup.java @@ -26,6 +26,11 @@ public interface FunctionGroup extends Named { public Set getFunctionDescriptors() { return Collections.emptySet(); } + + @Override + public String toString() { + return "EMPTY"; + } }; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java index 402b5c83597..008c53e20bb 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java @@ -42,7 +42,7 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme super(containingDeclaration); this.scopeForMemberLookup = new WritableScopeImpl(JetScope.EMPTY, this, trace.getErrorHandler()).setDebugName("MemberLookup"); this.scopeForSupertypeResolution = new WritableScopeImpl(outerScope, this, trace.getErrorHandler()).setDebugName("SupertypeResolution"); - this.scopeForMemberResolution = new WritableScopeImpl(new ChainedScope(this, scopeForMemberLookup, scopeForSupertypeResolution), this, trace.getErrorHandler()).setDebugName("MemberResolution"); + this.scopeForMemberResolution = new WritableScopeImpl(scopeForSupertypeResolution, this, trace.getErrorHandler()).setDebugName("MemberResolution"); this.kind = kind; } @@ -87,6 +87,7 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme public void addPropertyDescriptor(@NotNull PropertyDescriptor propertyDescriptor) { properties.add(propertyDescriptor); scopeForMemberLookup.addVariableDescriptor(propertyDescriptor); + scopeForMemberResolution.addVariableDescriptor(propertyDescriptor); } @NotNull @@ -98,6 +99,7 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme public void addFunctionDescriptor(@NotNull FunctionDescriptor functionDescriptor) { functions.add(functionDescriptor); scopeForMemberLookup.addFunctionDescriptor(functionDescriptor); + scopeForMemberResolution.addFunctionDescriptor(functionDescriptor); } @NotNull @@ -118,6 +120,7 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme @Override public void addClassifierDescriptor(@NotNull MutableClassDescriptor classDescriptor) { scopeForMemberLookup.addClassifierDescriptor(classDescriptor); + scopeForMemberResolution.addClassifierDescriptor(classDescriptor); } public void addSupertype(@NotNull JetType supertype) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/SemanticWhitespaceAwarePsiBuilderAdapter.java b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/SemanticWhitespaceAwarePsiBuilderAdapter.java index 9a72d5aa570..ee3ed333a45 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/SemanticWhitespaceAwarePsiBuilderAdapter.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/SemanticWhitespaceAwarePsiBuilderAdapter.java @@ -1,6 +1,6 @@ package org.jetbrains.jet.lang.parsing; -import com.intellij.lang.java.parser.JavaParserUtil.PsiBuilderAdapter; +import com.intellij.lang.impl.PsiBuilderAdapter; /** * @author abreslav diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/SemanticWhitespaceAwarePsiBuilderImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/SemanticWhitespaceAwarePsiBuilderImpl.java index e62d5096a90..d1d60ef58c3 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/SemanticWhitespaceAwarePsiBuilderImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/SemanticWhitespaceAwarePsiBuilderImpl.java @@ -2,7 +2,7 @@ package org.jetbrains.jet.lang.parsing; import com.intellij.lang.PsiBuilder; -import com.intellij.lang.java.parser.JavaParserUtil.PsiBuilderAdapter; +import com.intellij.lang.impl.PsiBuilderAdapter; import com.intellij.psi.TokenType; import com.intellij.psi.tree.IElementType; import org.jetbrains.jet.lexer.JetTokens; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java index e7907de6ad0..2b0b2645e6a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java @@ -41,89 +41,6 @@ public class ClassDescriptorResolver { this.annotationResolver = new AnnotationResolver(semanticServices, trace); } - @Nullable - public ClassDescriptor resolveClassDescriptor(@NotNull JetScope scope, @NotNull JetClass classElement) { - final ClassDescriptorImpl classDescriptor = new ClassDescriptorImpl( - scope.getContainingDeclaration(), - annotationResolver.resolveAnnotations(scope, classElement.getModifierList()), - JetPsiUtil.safeName(classElement.getName())); - - trace.record(BindingContext.CLASS, classElement, classDescriptor); - - final WritableScope parameterScope = new WritableScopeImpl(scope, classDescriptor, trace.getErrorHandler()); - - // This call has side-effects on the parameterScope (fills it in) - List typeParameters - = resolveTypeParameters(classDescriptor, parameterScope, classElement.getTypeParameters()); - resolveGenericBounds(classElement, parameterScope, typeParameters); - - List delegationSpecifiers = classElement.getDelegationSpecifiers(); - // TODO : assuming that the hierarchy is acyclic - Collection supertypes = delegationSpecifiers.isEmpty() - ? Collections.singleton(JetStandardClasses.getAnyType()) - : resolveDelegationSpecifiers(parameterScope, delegationSpecifiers, typeResolver); -// for (JetType supertype: supertypes) { -// if (supertype.getConstructor().isSealed()) { -// trace.getErrorHandler().genericError(classElement.getNameAsDeclaration().getNode(), "Class " + classElement.getName() + " can not extend final type " + supertype); -// } -// } - boolean open = classElement.hasModifier(JetTokens.OPEN_KEYWORD); - - final WritableScope memberDeclarations = new WritableScopeImpl(JetScope.EMPTY, classDescriptor, trace.getErrorHandler()); - - List declarations = classElement.getDeclarations(); - for (JetDeclaration declaration : declarations) { - declaration.accept(new JetVisitorVoid() { - @Override - public void visitProperty(JetProperty property) { - if (property.getPropertyTypeRef() != null) { - memberDeclarations.addVariableDescriptor(resolvePropertyDescriptor(classDescriptor, parameterScope, property)); - } else { - // TODO : Caution: a cyclic dependency possible - throw new UnsupportedOperationException(); - } - } - - @Override - public void visitNamedFunction(JetNamedFunction function) { - if (function.getReturnTypeRef() != null) { - memberDeclarations.addFunctionDescriptor(resolveFunctionDescriptor(classDescriptor, parameterScope, function)); - } else { - // TODO : Caution: a cyclic dependency possible - throw new UnsupportedOperationException(); - } - } - - @Override - public void visitJetElement(JetElement element) { - throw new UnsupportedOperationException(element.toString()); - } - }); - } - - WritableFunctionGroup constructors = new WritableFunctionGroup(""); - classDescriptor.initialize( - !open, - typeParameters, - supertypes, - memberDeclarations, - constructors, - null - ); - for (JetConstructor constructor : classElement.getSecondaryConstructors()) { - ConstructorDescriptorImpl functionDescriptor = resolveSecondaryConstructorDescriptor(memberDeclarations, classDescriptor, constructor); - functionDescriptor.setReturnType(classDescriptor.getDefaultType()); - constructors.addFunction(functionDescriptor); - } - ConstructorDescriptorImpl primaryConstructorDescriptor = resolvePrimaryConstructorDescriptor(scope, classDescriptor, classElement); - if (primaryConstructorDescriptor != null) { - primaryConstructorDescriptor.setReturnType(classDescriptor.getDefaultType()); - constructors.addFunction(primaryConstructorDescriptor); - classDescriptor.setPrimaryConstructor(primaryConstructorDescriptor); - } - return classDescriptor; - } - public void resolveMutableClassDescriptor(@NotNull JetClass classElement, @NotNull MutableClassDescriptor descriptor) { // TODO : Where-clause List typeParameters = Lists.newArrayList(); @@ -398,7 +315,7 @@ public class ClassDescriptorResolver { return jetType; } - private Collection resolveDelegationSpecifiers(JetScope extensibleScope, List delegationSpecifiers, @NotNull TypeResolver resolver) { + public Collection resolveDelegationSpecifiers(JetScope extensibleScope, List delegationSpecifiers, @NotNull TypeResolver resolver) { if (delegationSpecifiers.isEmpty()) { return Collections.emptyList(); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/SubstitutingScope.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/SubstitutingScope.java index bfa03e0f1be..8d4392eee57 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/SubstitutingScope.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/SubstitutingScope.java @@ -1,12 +1,15 @@ 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.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; -import org.jetbrains.jet.lang.types.*; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.TypeSubstitutor; import java.util.Collection; +import java.util.Map; /** * @author abreslav @@ -15,7 +18,9 @@ public class SubstitutingScope implements JetScope { private final JetScope workerScope; private final TypeSubstitutor substitutor; - private Collection allDescriptors; + + private Map functionGroups = null; + private Collection allDescriptors = null; public SubstitutingScope(JetScope workerScope, @NotNull TypeSubstitutor substitutor) { this.workerScope = workerScope; @@ -58,11 +63,27 @@ public class SubstitutingScope implements JetScope { @NotNull @Override public FunctionGroup getFunctionGroup(@NotNull String name) { - FunctionGroup functionGroup = workerScope.getFunctionGroup(name); - if (substitutor.isEmpty() || functionGroup.isEmpty()) { - return functionGroup; + if (substitutor.isEmpty()) { + return workerScope.getFunctionGroup(name); } - return new LazySubstitutingFunctionGroup(substitutor, functionGroup); + if (functionGroups == null) { + functionGroups = Maps.newHashMap(); + } + FunctionGroup cachedGroup = functionGroups.get(name); + if (cachedGroup != null) { + return cachedGroup; + } + + FunctionGroup functionGroup = workerScope.getFunctionGroup(name); + FunctionGroup result; + if (functionGroup.isEmpty()) { + result = FunctionGroup.EMPTY; + } + else { + result = new LazySubstitutingFunctionGroup(substitutor, functionGroup); + } + functionGroups.put(name, result); + return result; } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java index 74a5f264c74..451fcf52346 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java @@ -291,7 +291,4 @@ public class TypeHierarchyResolver { } } } - - - } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index 6440ad0fef3..792948941c8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -472,17 +472,9 @@ public class CallResolver { @NotNull private OverloadResolutionResult computeResultAndReportErrors(BindingTrace trace, TracingStrategy tracing, Map successfulCandidates, Set failedCandidates, Set dirtyCandidates, Map traces) { + // TODO : maybe it's better to filter overrides out first, and only then look for the maximally specific if (successfulCandidates.size() > 0) { - if (successfulCandidates.size() == 1) { - Map.Entry entry = successfulCandidates.entrySet().iterator().next(); - Descriptor functionDescriptor = entry.getKey(); - Descriptor result = entry.getValue(); - - TemporaryBindingTrace temporaryTrace = traces.get(functionDescriptor); - temporaryTrace.commit(); - return OverloadResolutionResult.success(result); - } - else { + if (successfulCandidates.size() != 1) { Map cleanCandidates = Maps.newLinkedHashMap(successfulCandidates); cleanCandidates.keySet().removeAll(dirtyCandidates); if (cleanCandidates.isEmpty()) { @@ -498,37 +490,41 @@ public class CallResolver { return OverloadResolutionResult.success(maximallySpecificGenericsDiscriminated); } + Set noOverrides = filterOverrides(successfulCandidates.keySet()); if (dirtyCandidates.isEmpty()) { - StringBuilder stringBuilder = new StringBuilder(); - for (Descriptor functionDescriptor : successfulCandidates.keySet()) { - stringBuilder.append(DescriptorRenderer.TEXT.render(functionDescriptor)).append(" "); - } - - tracing.reportOverallResolutionError(trace, "Overload resolution ambiguity: " + stringBuilder); + tracing.reportOverallResolutionError(trace, "Overload resolution ambiguity: " + + makeErrorMessageForMultipleDescriptors(noOverrides)); } - - tracing.recordAmbiguity(trace, successfulCandidates.keySet()); - - return OverloadResolutionResult.ambiguity(successfulCandidates.keySet()); + + tracing.recordAmbiguity(trace, noOverrides); + + return OverloadResolutionResult.ambiguity(noOverrides); + } + else { + Map.Entry entry = successfulCandidates.entrySet().iterator().next(); + Descriptor functionDescriptor = entry.getKey(); + Descriptor result = entry.getValue(); + + TemporaryBindingTrace temporaryTrace = traces.get(functionDescriptor); + temporaryTrace.commit(); + return OverloadResolutionResult.success(result); } } else if (!failedCandidates.isEmpty()) { - if (failedCandidates.size() == 1) { - Descriptor functionDescriptor = failedCandidates.iterator().next(); - TemporaryBindingTrace temporaryTrace = traces.get(functionDescriptor); - temporaryTrace.commit(); - return OverloadResolutionResult.singleFailedCandidate(failedCandidates.iterator().next()); - } - else { - StringBuilder stringBuilder = new StringBuilder("\n"); - for (Descriptor functionDescriptor : failedCandidates) { - stringBuilder.append(DescriptorRenderer.TEXT.render(functionDescriptor)).append("\n"); + if (failedCandidates.size() != 1) { + Set noOverrides = filterOverrides(failedCandidates); + if (noOverrides.size() != 1) { + tracing.reportOverallResolutionError(trace, "None of the following functions can be called with the arguments supplied: " + + makeErrorMessageForMultipleDescriptors(noOverrides)); + tracing.recordAmbiguity(trace, noOverrides); + return OverloadResolutionResult.manyFailedCandidates(noOverrides); } - - tracing.reportOverallResolutionError(trace, "None of the following functions can be called with the arguments supplied: " + stringBuilder); - tracing.recordAmbiguity(trace, failedCandidates); - return OverloadResolutionResult.manyFailedCandidates(failedCandidates); + failedCandidates = noOverrides; } + Descriptor functionDescriptor = failedCandidates.iterator().next(); + TemporaryBindingTrace temporaryTrace = traces.get(functionDescriptor); + temporaryTrace.commit(); + return OverloadResolutionResult.singleFailedCandidate(failedCandidates.iterator().next()); } else { tracing.reportUnresolvedReference(trace); @@ -536,6 +532,28 @@ public class CallResolver { } } + private StringBuilder makeErrorMessageForMultipleDescriptors(Set candidates) { + StringBuilder stringBuilder = new StringBuilder("\n"); + for (Descriptor functionDescriptor : candidates) { + stringBuilder.append(DescriptorRenderer.TEXT.render(functionDescriptor)).append("\n"); + } + return stringBuilder; + } + + private Set filterOverrides(Set candidateSet) { + Set candidates = Sets.newLinkedHashSet(); + outerLoop: + for (Descriptor me : candidateSet) { + for (Descriptor other : candidateSet) { + if (OverloadingConflictResolver.overrides(other, me)) { + continue outerLoop; + } + } + candidates.add(me); + } + return candidates; + } + private boolean checkValueArgumentTypes(JetScope scope, JetTypeInferrer.Services temporaryServices, Map argumentsToParameters, Flag dirty, Function parameterMap) { boolean result = true; for (Map.Entry entry : argumentsToParameters.entrySet()) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java index 2a9887e3c2c..c25f75451b0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java @@ -120,7 +120,7 @@ import java.util.Set; return false; } - private boolean overrides(@NotNull Descriptor f, @NotNull Descriptor g) { + public static boolean overrides(@NotNull Descriptor f, @NotNull Descriptor g) { Set overriddenDescriptors = Sets.newHashSet(); getAllOverriddenDescriptors(f.getOriginal(), overriddenDescriptors); CallableDescriptor originalG = g.getOriginal(); @@ -130,7 +130,7 @@ import java.util.Set; return false; } - private void getAllOverriddenDescriptors(@NotNull CallableDescriptor current, @NotNull Set overriddenDescriptors) { + private static void getAllOverriddenDescriptors(@NotNull CallableDescriptor current, @NotNull Set overriddenDescriptors) { if (overriddenDescriptors.contains(current)) return; for (CallableDescriptor descriptor : current.getOriginal().getOverriddenDescriptors()) { getAllOverriddenDescriptors(descriptor, overriddenDescriptors); diff --git a/idea/testData/codegen/regressions/kt259.jet b/idea/testData/codegen/regressions/kt259.jet index dada6e9c2cd..e11e74f179d 100644 --- a/idea/testData/codegen/regressions/kt259.jet +++ b/idea/testData/codegen/regressions/kt259.jet @@ -1,10 +1,16 @@ class A() {} -class B() { +open class B() { fun isT (a : Any?) : Boolean { return a is T } } +class C() : B() { +} + +class D() : B>() { +} + fun t1() : Boolean { val a = A() if(a !is A) return false @@ -148,6 +154,18 @@ fun t24 () : Boolean { return true } +fun t25 () : Boolean { + val c = C() + if(!c.isT("aaa")) return false + return true +} + +fun t26 () : Boolean { + val d = D() + if(!d.isT(B())) return false + return true +} + fun box() : String { if(!t1()) { return "t1 failed" @@ -221,5 +239,11 @@ fun box() : String { if(!t24()) { return "t24 failed" } + if(!t25()) { + return "t25 failed" + } + if(!t26()) { + return "t26 failed" + } return "OK" } \ No newline at end of file diff --git a/idea/testData/codegen/regressions/kt297.jet b/idea/testData/codegen/regressions/kt297.jet new file mode 100644 index 00000000000..0a6ad8f82a5 --- /dev/null +++ b/idea/testData/codegen/regressions/kt297.jet @@ -0,0 +1,4 @@ +// KT-297 Overload resolution ambiguity with required in trait +trait ALE : java.util.ArrayList { + fun getOrValue(index: Int, value : T) : T = if(index >= 0 && index < size()) get(index) else value +} \ No newline at end of file diff --git a/idea/testData/codegen/traits/multiple.jet b/idea/testData/codegen/traits/multiple.jet new file mode 100644 index 00000000000..c471506e9c5 --- /dev/null +++ b/idea/testData/codegen/traits/multiple.jet @@ -0,0 +1,15 @@ +trait AL { + fun get(index: Int) : Any? = null +} + +trait ALE : AL { + fun getOrNull(index: Int, value : T) = get(index) as? T ?: value +} + +class SmartArrayList() : ALE { +} + +fun box() : String { + val c = SmartArrayList() + return if("239" == c.getOrNull(0, "239")) "OK" else "fail" +} diff --git a/idea/testData/codegen/traits/withRequired.jet b/idea/testData/codegen/traits/withRequired.jet new file mode 100644 index 00000000000..64e4df814ee --- /dev/null +++ b/idea/testData/codegen/traits/withRequired.jet @@ -0,0 +1,15 @@ +open class AL { + fun get(index: Int) : T? = null +} + +trait ALE : AL { + fun getOrValue(index: Int, value : T) : T = get(index) ?: value +} + +class SmartArrayList() : ALE, AL { +} + +fun box() : String { + val c = SmartArrayList() + return if("239" == c.getOrValue(0, "239")) "OK" else "fail" +} diff --git a/idea/testData/resolve/regressions/kt300.jet b/idea/testData/resolve/regressions/kt300.jet new file mode 100644 index 00000000000..aaaf340f3a7 --- /dev/null +++ b/idea/testData/resolve/regressions/kt300.jet @@ -0,0 +1,9 @@ +// KT-300 Overload ambiguity while accessing range + +class MyRange() : Range { + ~in~override fun contains(item: Int) = true +} + +fun foo(x: Int?, range: MyRange) { + x `in`in range // Int? found, but Int expected +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/codegen/TraitsTest.java b/idea/tests/org/jetbrains/jet/codegen/TraitsTest.java index 3558c42e455..384c103b9a3 100644 --- a/idea/tests/org/jetbrains/jet/codegen/TraitsTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/TraitsTest.java @@ -10,4 +10,14 @@ public class TraitsTest extends CodegenTestCase { blackBoxFile("traits/simple.jet"); System.out.println(generateToText()); } + + public void testWithRequired () throws Exception { + blackBoxFile("traits/withRequired.jet"); + System.out.println(generateToText()); + } + + public void testMultiple () throws Exception { +// blackBoxFile("traits/multiple.jet"); +// System.out.println(generateToText()); + } } diff --git a/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java b/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java index d4843618aa9..39f2db4abfa 100644 --- a/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java @@ -131,6 +131,7 @@ public class TypeInfoTest extends CodegenTestCase { public void testKt259() throws Exception { blackBoxFile("regressions/kt259.jet"); + System.out.println(generateToText()); } } diff --git a/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java b/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java index b3e2b853a99..d531312e086 100644 --- a/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java +++ b/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java @@ -6,19 +6,20 @@ import com.intellij.openapi.application.PathManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetTestCaseBase; import org.jetbrains.jet.JetTestUtils; import org.jetbrains.jet.lang.ErrorHandler; 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.JetChangeUtil; -import org.jetbrains.jet.lang.psi.JetClass; -import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.resolve.java.JavaPackageScope; import org.jetbrains.jet.lang.resolve.java.JavaSemanticServices; import org.jetbrains.jet.lang.types.*; +import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.parsing.JetParsingTest; import java.io.File; @@ -34,6 +35,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { private ClassDefinitions classDefinitions; private ClassDescriptorResolver classDescriptorResolver; private JetScope scopeWithImports; + private TypeResolver typeResolver; @Override public void setUp() throws Exception { @@ -43,6 +45,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { classDefinitions = new ClassDefinitions(); classDescriptorResolver = semanticServices.getClassDescriptorResolver(JetTestUtils.DUMMY_TRACE); scopeWithImports = addImports(classDefinitions.BASIC_SCOPE); + typeResolver = new TypeResolver(semanticServices, JetTestUtils.DUMMY_TRACE, true); } @Override @@ -592,7 +595,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { if (CLASSES.isEmpty()) { for (String classDeclaration : CLASS_DECLARATIONS) { JetClass classElement = JetChangeUtil.createClass(getProject(), classDeclaration); - ClassDescriptor classDescriptor = classDescriptorResolver.resolveClassDescriptor(this, classElement); + ClassDescriptor classDescriptor = resolveClassDescriptor(this, classElement); CLASSES.put(classDescriptor.getName(), classDescriptor); } } @@ -622,5 +625,91 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { return writableFunctionGroup; } }; + + @Nullable + public ClassDescriptor resolveClassDescriptor(@NotNull JetScope scope, @NotNull JetClass classElement) { + final ClassDescriptorImpl classDescriptor = new ClassDescriptorImpl( + scope.getContainingDeclaration(), + Collections.emptyList(), + JetPsiUtil.safeName(classElement.getName())); + + BindingTrace trace = JetTestUtils.DUMMY_TRACE; + + trace.record(BindingContext.CLASS, classElement, classDescriptor); + + final WritableScope parameterScope = new WritableScopeImpl(scope, classDescriptor, trace.getErrorHandler()); + + // This call has side-effects on the parameterScope (fills it in) + List typeParameters + = classDescriptorResolver.resolveTypeParameters(classDescriptor, parameterScope, classElement.getTypeParameters()); + classDescriptorResolver.resolveGenericBounds(classElement, parameterScope, typeParameters); + + List delegationSpecifiers = classElement.getDelegationSpecifiers(); + // TODO : assuming that the hierarchy is acyclic + Collection supertypes = delegationSpecifiers.isEmpty() + ? Collections.singleton(JetStandardClasses.getAnyType()) + : classDescriptorResolver.resolveDelegationSpecifiers(parameterScope, delegationSpecifiers, typeResolver); + // for (JetType supertype: supertypes) { + // if (supertype.getConstructor().isSealed()) { + // trace.getErrorHandler().genericError(classElement.getNameAsDeclaration().getNode(), "Class " + classElement.getName() + " can not extend final type " + supertype); + // } + // } + boolean open = classElement.hasModifier(JetTokens.OPEN_KEYWORD); + + final WritableScope memberDeclarations = new WritableScopeImpl(JetScope.EMPTY, classDescriptor, trace.getErrorHandler()); + + List declarations = classElement.getDeclarations(); + for (JetDeclaration declaration : declarations) { + declaration.accept(new JetVisitorVoid() { + @Override + public void visitProperty(JetProperty property) { + if (property.getPropertyTypeRef() != null) { + memberDeclarations.addVariableDescriptor(classDescriptorResolver.resolvePropertyDescriptor(classDescriptor, parameterScope, property)); + } else { + // TODO : Caution: a cyclic dependency possible + throw new UnsupportedOperationException(); + } + } + + @Override + public void visitNamedFunction(JetNamedFunction function) { + if (function.getReturnTypeRef() != null) { + memberDeclarations.addFunctionDescriptor(classDescriptorResolver.resolveFunctionDescriptor(classDescriptor, parameterScope, function)); + } else { + // TODO : Caution: a cyclic dependency possible + throw new UnsupportedOperationException(); + } + } + + @Override + public void visitJetElement(JetElement element) { + throw new UnsupportedOperationException(element.toString()); + } + }); + } + + WritableFunctionGroup constructors = new WritableFunctionGroup(""); + classDescriptor.initialize( + !open, + typeParameters, + supertypes, + memberDeclarations, + constructors, + null + ); + for (JetConstructor constructor : classElement.getSecondaryConstructors()) { + ConstructorDescriptorImpl functionDescriptor = classDescriptorResolver.resolveSecondaryConstructorDescriptor(memberDeclarations, classDescriptor, constructor); + functionDescriptor.setReturnType(classDescriptor.getDefaultType()); + constructors.addFunction(functionDescriptor); + } + ConstructorDescriptorImpl primaryConstructorDescriptor = classDescriptorResolver.resolvePrimaryConstructorDescriptor(scope, classDescriptor, classElement); + if (primaryConstructorDescriptor != null) { + primaryConstructorDescriptor.setReturnType(classDescriptor.getDefaultType()); + constructors.addFunction(primaryConstructorDescriptor); + classDescriptor.setPrimaryConstructor(primaryConstructorDescriptor); + } + return classDescriptor; + } + } }