JET-26 Check bounds in generic types

+ Working on JET-25 Support method overriding
This commit is contained in:
Andrey Breslav
2011-05-10 21:37:17 +04:00
parent 7f6440c439
commit 7c263c3e95
16 changed files with 253 additions and 39 deletions
@@ -132,9 +132,12 @@ public class JetPsiChecker implements Annotator {
}
private void putBackingfieldAnnotation(AnnotationHolder holder, JetNamedDeclaration element) {
holder.createInfoAnnotation(
element.getNameIdentifier(),
"This property has a backing field")
.setTextAttributes(JetHighlighter.JET_PROPERTY_WITH_BACKING_FIELD_IDENTIFIER);
PsiElement nameIdentifier = element.getNameIdentifier();
if (nameIdentifier != null) {
holder.createInfoAnnotation(
nameIdentifier,
"This property has a backing field")
.setTextAttributes(JetHighlighter.JET_PROPERTY_WITH_BACKING_FIELD_IDENTIFIER);
}
}
}
@@ -29,7 +29,7 @@ public class ClassDescriptorImpl extends DeclarationDescriptorImpl implements Cl
public final ClassDescriptorImpl initialize(boolean sealed,
@NotNull List<TypeParameterDescriptor> typeParameters,
@NotNull Collection<? extends JetType> superclasses,
@NotNull Collection<JetType> superclasses,
@NotNull JetScope memberDeclarations,
@NotNull FunctionGroup constructors,
@Nullable ConstructorDescriptor primaryConstructor) {
@@ -2,11 +2,61 @@ package org.jetbrains.jet.lang.descriptors;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.types.TypeSubstitutor;
import java.util.List;
/**
* @author abreslav
*/
public interface NamespaceLike extends DeclarationDescriptor {
abstract class Adapter implements NamespaceLike {
private final DeclarationDescriptor descriptor;
public Adapter(DeclarationDescriptor descriptor) {
this.descriptor = descriptor;
}
@Override
@NotNull
public DeclarationDescriptor getOriginal() {
return descriptor.getOriginal();
}
@Override
@Nullable
public DeclarationDescriptor getContainingDeclaration() {
return descriptor.getContainingDeclaration();
}
@Override
public DeclarationDescriptor substitute(TypeSubstitutor substitutor) {
return descriptor.substitute(substitutor);
}
@Override
public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
return descriptor.accept(visitor, data);
}
@Override
public void acceptVoid(DeclarationDescriptorVisitor<Void, Void> visitor) {
descriptor.acceptVoid(visitor);
}
@Override
public List<Annotation> getAnnotations() {
return descriptor.getAnnotations();
}
@Override
@NotNull
public String getName() {
return descriptor.getName();
}
}
@Nullable
NamespaceDescriptor getNamespace(String name);
@@ -1,5 +1,6 @@
package org.jetbrains.jet.lang.psi;
import com.google.common.collect.Lists;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
@@ -8,6 +9,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -19,6 +21,24 @@ public class JetFunctionType extends JetTypeElement {
super(node);
}
@NotNull
@Override
public List<JetTypeReference> getTypeArgumentsAsTypes() {
ArrayList<JetTypeReference> result = Lists.newArrayList();
JetTypeReference receiverTypeRef = getReceiverTypeRef();
if (receiverTypeRef != null) {
result.add(receiverTypeRef);
}
for (JetParameter jetParameter : getParameters()) {
result.add(jetParameter.getTypeReference());
}
JetTypeReference returnTypeRef = getReturnTypeRef();
if (returnTypeRef != null) {
result.add(returnTypeRef);
}
return result;
}
@Override
public void accept(JetVisitor visitor) {
visitor.visitFunctionType(this);
@@ -2,7 +2,6 @@ package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.JetNodeTypes;
import java.util.List;
@@ -14,6 +13,12 @@ public class JetNullableType extends JetTypeElement {
super(node);
}
@NotNull
@Override
public List<JetTypeReference> getTypeArgumentsAsTypes() {
return getInnerType().getTypeArgumentsAsTypes();
}
@Override
public void accept(JetVisitor visitor) {
visitor.visitNullableType(this);
@@ -3,6 +3,9 @@ package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
/**
* @author max
*/
@@ -11,6 +14,12 @@ public class JetSelfType extends JetTypeElement {
super(node);
}
@NotNull
@Override
public List<JetTypeReference> getTypeArgumentsAsTypes() {
return Collections.emptyList();
}
@Override
public void accept(JetVisitor visitor) {
visitor.visitSelfType(this);
@@ -14,6 +14,12 @@ public class JetTupleType extends JetTypeElement {
super(node);
}
@NotNull
@Override
public List<JetTypeReference> getTypeArgumentsAsTypes() {
return getComponentTypeRefs();
}
@Override
public void accept(JetVisitor visitor) {
visitor.visitTupleType(this);
@@ -3,6 +3,8 @@ package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* @author max
*/
@@ -10,4 +12,8 @@ public abstract class JetTypeElement extends JetElement {
public JetTypeElement(@NotNull ASTNode node) {
super(node);
}
@NotNull
public abstract List<JetTypeReference> getTypeArgumentsAsTypes();
}
@@ -1,5 +1,6 @@
package org.jetbrains.jet.lang.psi;
import com.google.common.collect.Lists;
import com.intellij.lang.ASTNode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -30,12 +31,23 @@ public class JetUserType extends JetTypeElement {
return (JetTypeArgumentList) findChildByType(JetNodeTypes.TYPE_ARGUMENT_LIST);
}
@NotNull
public List<JetTypeProjection> getTypeArguments() {
// TODO: empty elements in PSI
JetTypeArgumentList typeArgumentList = getTypeArgumentList();
return typeArgumentList == null ? Collections.<JetTypeProjection>emptyList() : typeArgumentList.getArguments();
}
@NotNull
@Override
public List<JetTypeReference> getTypeArgumentsAsTypes() {
List<JetTypeReference> result = Lists.newArrayList();
for (JetTypeProjection projection : getTypeArguments()) {
result.add(projection.getTypeReference());
}
return result;
}
@Nullable @IfNotParsed
public JetSimpleNameExpression getReferenceExpression() {
return (JetSimpleNameExpression) findChildByType(JetNodeTypes.REFERENCE_EXPRESSION);
@@ -25,11 +25,13 @@ public class ClassDescriptorResolver {
private final JetSemanticServices semanticServices;
private final TypeResolver typeResolver;
private final TypeResolver typeResolverNotCheckingBounds;
private final BindingTrace trace;
public ClassDescriptorResolver(JetSemanticServices semanticServices, BindingTrace trace) {
this.semanticServices = semanticServices;
this.typeResolver = new TypeResolver(trace, semanticServices);
this.typeResolver = new TypeResolver(semanticServices, trace, true);
this.typeResolverNotCheckingBounds = new TypeResolver(semanticServices, trace, false);
this.trace = trace;
}
@@ -50,7 +52,7 @@ public class ClassDescriptorResolver {
List<JetDelegationSpecifier> delegationSpecifiers = classElement.getDelegationSpecifiers();
// TODO : assuming that the hierarchy is acyclic
Collection<? extends JetType> supertypes = delegationSpecifiers.isEmpty()
Collection<JetType> supertypes = delegationSpecifiers.isEmpty()
? Collections.singleton(JetStandardClasses.getAnyType())
: resolveDelegationSpecifiers(parameterScope, delegationSpecifiers);
boolean open = classElement.hasModifier(JetTokens.OPEN_KEYWORD);
@@ -107,27 +109,33 @@ public class ClassDescriptorResolver {
typeConstructor
);
// List<JetDelegationSpecifier> delegationSpecifiers = classElement.getDelegationSpecifiers();
// TODO : assuming that the hierarchy is acyclic
// Collection<? extends JetType> superclasses = delegationSpecifiers.isEmpty()
// ? Collections.singleton(JetStandardClasses.getAnyType())
// : resolveDelegationSpecifiers(parameterScope, delegationSpecifiers);
// TODO : UGLY HACK
// supertypes.addAll(superclasses);
// TODO : importing may be a bad idea
// for (JetType supertype : superclasses) {
// assert supertype != null : classElement.getName();
// parameterScope.importScope(supertype.getMemberScope());
// }
descriptor.getClassHeaderScope().setThisType(descriptor.getDefaultType());
trace.recordDeclarationResolution(classElement, descriptor);
}
public void resolveGenericBounds(@NotNull JetClass jetClass, @NotNull MutableClassDescriptor classDescriptor) {
List<JetTypeParameter> typeParameters = jetClass.getTypeParameters();
List<TypeParameterDescriptor> parameters = classDescriptor.getTypeConstructor().getParameters();
for (int i = 0, typeParametersSize = typeParameters.size(); i < typeParametersSize; i++) {
JetTypeParameter jetTypeParameter = typeParameters.get(i);
TypeParameterDescriptor typeParameterDescriptor = parameters.get(i);
JetTypeReference extendsBound = jetTypeParameter.getExtendsBound();
if (extendsBound != null) {
typeParameterDescriptor.addUpperBound(typeResolverNotCheckingBounds.resolveType(classDescriptor.getClassHeaderScope(), extendsBound));
}
}
// TODO : Bounds from with
}
public void resolveSupertypes(@NotNull JetClass jetClass, @NotNull MutableClassDescriptor descriptor) {
List<JetDelegationSpecifier> delegationSpecifiers = jetClass.getDelegationSpecifiers();
// TODO : assuming that the hierarchy is acyclic
Collection<? extends JetType> superclasses = delegationSpecifiers.isEmpty()
? Collections.singleton(JetStandardClasses.getAnyType())
: resolveDelegationSpecifiers(descriptor.getClassHeaderScope(), delegationSpecifiers);
((TypeConstructorImpl) descriptor.getTypeConstructor()).getSupertypes().addAll(superclasses);
}
public void resolveMutableClassDescriptor(@NotNull JetScope scope, @NotNull JetClass classElement, @NotNull MutableClassDescriptor descriptor) {
descriptor.setName(JetPsiUtil.safeName(classElement.getName()));
@@ -317,7 +325,7 @@ public class ClassDescriptorResolver {
return typeParameterDescriptor;
}
public Collection<? extends JetType> resolveDelegationSpecifiers(WritableScope extensibleScope, List<JetDelegationSpecifier> delegationSpecifiers) {
private Collection<JetType> resolveDelegationSpecifiers(WritableScope extensibleScope, List<JetDelegationSpecifier> delegationSpecifiers) {
if (delegationSpecifiers.isEmpty()) {
return Collections.emptyList();
}
@@ -569,4 +577,37 @@ public class ClassDescriptorResolver {
return propertyDescriptor;
}
public void checkBounds(JetTypeReference typeReference, JetType type) {
if (ErrorUtils.isErrorType(type)) return;
JetTypeElement typeElement = typeReference.getTypeElement();
if (typeElement == null) return;
List<TypeParameterDescriptor> parameters = type.getConstructor().getParameters();
List<TypeProjection> arguments = type.getArguments();
assert parameters.size() == arguments.size();
List<JetTypeReference> typeReferences = typeElement.getTypeArgumentsAsTypes();
assert typeReferences.size() == arguments.size() : typeElement.getText();
for (int i = 0, projectionsSize = typeReferences.size(); i < projectionsSize; i++) {
JetTypeReference argumentTypeReference = typeReferences.get(i);
if (argumentTypeReference == null) continue;
JetType typeArgument = arguments.get(i).getType();
checkBounds(argumentTypeReference, typeArgument);
TypeParameterDescriptor typeParameterDescriptor = parameters.get(i);
checkBounds(argumentTypeReference, typeArgument, typeParameterDescriptor);
}
}
public void checkBounds(@NotNull JetTypeReference argumentTypeReference, @NotNull JetType typeArgument, @NotNull TypeParameterDescriptor typeParameterDescriptor) {
for (JetType bound : typeParameterDescriptor.getUpperBounds()) {
if (!semanticServices.getTypeChecker().isSubtypeOf(typeArgument, bound)) {
trace.getErrorHandler().genericError(argumentTypeReference.getNode(), "An upper bound " + bound + " is violated"); // TODO : Message
}
}
}
}
@@ -123,7 +123,7 @@ public class TopDownAnalyzer {
trace.recordDeclarationResolution(namespace, namespaceDescriptor);
}
WritableScope namespaceScope = new WritableScopeImpl(outerScope, owner, trace.getErrorHandler(), null);
WritableScope namespaceScope = new WritableScopeImpl(outerScope, owner, trace.getErrorHandler(), null);
namespaceScopes.put(namespace, namespaceScope);
for (JetImportDirective importDirective : importDirectives) {
@@ -143,8 +143,23 @@ public class TopDownAnalyzer {
}
}
// TODO: !!!
// collectNamespacesAndClassifiers(namespaceScope, namespaceDescriptor, namespace.getDeclarations());
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());
}
@Override
@@ -183,11 +198,34 @@ public class TopDownAnalyzer {
}
private void resolveTypesInClassHeaders() {
throw new UnsupportedOperationException(); // TODO
for (Map.Entry<JetClass, MutableClassDescriptor> entry : classes.entrySet()) {
JetClass jetClass = entry.getKey();
MutableClassDescriptor descriptor = entry.getValue();
classDescriptorResolver.resolveGenericBounds(jetClass, descriptor);
classDescriptorResolver.resolveSupertypes(jetClass, descriptor);
}
}
private void checkGenericBoundsInClassHeaders() {
throw new UnsupportedOperationException(); // TODO
for (Map.Entry<JetClass, MutableClassDescriptor> entry : classes.entrySet()) {
JetClass jetClass = entry.getKey();
for (JetDelegationSpecifier delegationSpecifier : jetClass.getDelegationSpecifiers()) {
JetType type = trace.resolveTypeReference(delegationSpecifier.getTypeReference());
classDescriptorResolver.checkBounds(delegationSpecifier.getTypeReference(), type);
}
for (JetTypeParameter jetTypeParameter : jetClass.getTypeParameters()) {
JetTypeReference extendsBound = jetTypeParameter.getExtendsBound();
if (extendsBound != null) {
JetType type = trace.resolveTypeReference(extendsBound);
classDescriptorResolver.checkBounds(extendsBound, type);
}
}
// TODO : where-bounds
}
}
private void resolveFunctionAndPropertyHeaders() {
@@ -426,6 +464,8 @@ public class TopDownAnalyzer {
checkIfPrimaryConstructorIsNecessary();
bindOverrides();
checkGenericBoundsInClassHeaders();
}
private void bindOverrides() {
@@ -16,12 +16,14 @@ import java.util.List;
*/
public class TypeResolver {
private final BindingTrace trace;
private final JetSemanticServices semanticServices;
private final BindingTrace trace;
private final boolean checkBounds;
public TypeResolver(BindingTrace trace, JetSemanticServices semanticServices) {
this.trace = trace;
public TypeResolver(JetSemanticServices semanticServices, BindingTrace trace, boolean checkBounds) {
this.semanticServices = semanticServices;
this.trace = trace;
this.checkBounds = checkBounds;
}
@NotNull
@@ -69,7 +71,8 @@ public class TypeResolver {
trace.recordReferenceResolution(referenceExpression, classifierDescriptor);
TypeConstructor typeConstructor = classifierDescriptor.getTypeConstructor();
List<TypeProjection> arguments = resolveTypeProjections(scope, typeConstructor, type.getTypeArguments());
int expectedArgumentCount = typeConstructor.getParameters().size();
List<TypeParameterDescriptor> parameters = typeConstructor.getParameters();
int expectedArgumentCount = parameters.size();
int actualArgumentCount = arguments.size();
if (ErrorUtils.isError(typeConstructor)) {
result[0] = new JetTypeImpl(
@@ -89,6 +92,17 @@ 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,
@@ -74,7 +74,7 @@ public class JetTypeInferrer {
public JetTypeInferrer(@NotNull BindingTrace trace, @NotNull JetFlowInformationProvider flowInformationProvider, @NotNull JetSemanticServices semanticServices) {
this.trace = new CachedBindingTrace(trace);
this.semanticServices = semanticServices;
this.typeResolver = new TypeResolver(trace, semanticServices);
this.typeResolver = new TypeResolver(semanticServices, trace, true);
this.classDescriptorResolver = semanticServices.getClassDescriptorResolver(trace);
this.flowInformationProvider = flowInformationProvider;
}
@@ -16,7 +16,7 @@ import java.util.List;
*/
public class TypeConstructorImpl extends AnnotatedImpl implements TypeConstructor {
private final List<TypeParameterDescriptor> parameters;
private Collection<? extends JetType> supertypes;
private Collection<JetType> supertypes;
private final String debugName;
private final boolean sealed;
@@ -29,7 +29,7 @@ public class TypeConstructorImpl extends AnnotatedImpl implements TypeConstructo
boolean sealed,
@NotNull String debugName,
@NotNull List<TypeParameterDescriptor> parameters,
@NotNull Collection<? extends JetType> supertypes) {
@NotNull Collection<JetType> supertypes) {
super(annotations);
this.declarationDescriptor = declarationDescriptor;
this.sealed = sealed;
@@ -46,7 +46,7 @@ public class TypeConstructorImpl extends AnnotatedImpl implements TypeConstructo
@Override
@NotNull
public Collection<? extends JetType> getSupertypes() {
public Collection<JetType> getSupertypes() {
return supertypes;
}
+8
View File
@@ -0,0 +1,8 @@
class A
class B<T : A>()
class C<T : B<<error>Int</error>>, X : {(B<<error>Char</error>>) : (B<<error>Any</error>>, B<A>)}>() : B<<error>Any</error>>() { // 2 errors
val a = new B<<error>Char</error>>() // error
val x : {(B<<error>Char</error>>) : B<<error>Any</error>>}
}
@@ -522,7 +522,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
}
private JetType makeType(JetScope scope, String typeStr) {
return new TypeResolver(BindingTrace.DUMMY, semanticServices).resolveType(scope, JetChangeUtil.createType(getProject(), typeStr));
return new TypeResolver(semanticServices, BindingTrace.DUMMY, true).resolveType(scope, JetChangeUtil.createType(getProject(), typeStr));
}
private class ClassDefinitions {