提交 4204db9c 编写于 作者: A Andrey Breslav

JET-84 Support generic parameter constraints for class objects

Done for classes only, not for functions
上级 a32c7a4d
......@@ -42,6 +42,6 @@ typeParameter
;
typeConstraint
: userType ":" type
: "class" "object" userType ":" type
: attributes SimpleName ":" type
: attributes "class" "object" SimpleName ":" type
;
\ No newline at end of file
......@@ -92,5 +92,15 @@ public abstract class JetDiagnostic {
}
}
// private final StackTraceElement[] stackTrace;
//
// protected JetDiagnostic() {
// stackTrace = Thread.currentThread().getStackTrace();
// }
//
// public StackTraceElement[] getStackTrace() {
// return stackTrace;
// }
public abstract void acceptHandler(@NonNls ErrorHandler handler);
}
......@@ -33,7 +33,7 @@ public class ConstructorDescriptorImpl extends FunctionDescriptorImpl implements
}
public ConstructorDescriptor initialize(@NotNull List<ValueParameterDescriptor> unsubstitutedValueParameters) {
super.initialize(null, Collections.<TypeParameterDescriptor>emptyList(), unsubstitutedValueParameters, getContainingDeclaration().getDefaultType());
super.initialize(null, Collections.<TypeParameterDescriptor>emptyList(), unsubstitutedValueParameters, null);
return this;
}
......
......@@ -52,7 +52,7 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements
return this;
}
public void setReturnType(JetType unsubstitutedReturnType) {
public void setReturnType(@NotNull JetType unsubstitutedReturnType) {
this.unsubstitutedReturnType = unsubstitutedReturnType;
}
......
......@@ -29,6 +29,7 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
private final WritableScope scopeForSupertypeResolution;
private MutableClassDescriptor classObjectDescriptor;
private JetType classObjectType;
private JetType defaultType;
public MutableClassDescriptor(@NotNull BindingTrace trace, @NotNull DeclarationDescriptor containingDeclaration, @NotNull JetScope outerScope) {
super(containingDeclaration);
......@@ -66,6 +67,9 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
public void addConstructor(@NotNull ConstructorDescriptor constructorDescriptor) {
assert constructorDescriptor.getContainingDeclaration() == this;
constructors.addFunction(constructorDescriptor);
if (defaultType != null) {
((ConstructorDescriptorImpl) constructorDescriptor).setReturnType(getDefaultType());
}
}
@Override
......@@ -115,10 +119,8 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
this.typeParameters.add(typeParameterDescriptor);
scopeForSupertypeResolution.addTypeParameterDescriptor(typeParameterDescriptor);
}
scopeForMemberResolution.setThisType(getDefaultType());
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Override
......@@ -138,18 +140,24 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
@NotNull
@Override
public TypeConstructor getTypeConstructor() {
if (typeConstructor == null) {
this.typeConstructor = new TypeConstructorImpl(
this,
Collections.<Annotation>emptyList(), // TODO : pass annotations from the class?
!open,
getName(),
typeParameters,
supertypes);
}
return typeConstructor;
}
public void createTypeConstructor() {
assert typeConstructor == null : typeConstructor;
this.typeConstructor = new TypeConstructorImpl(
this,
Collections.<Annotation>emptyList(), // TODO : pass annotations from the class?
!open,
getName(),
typeParameters,
supertypes);
scopeForMemberResolution.setThisType(getDefaultType());
for (FunctionDescriptor functionDescriptor : constructors.getFunctionDescriptors()) {
((ConstructorDescriptorImpl) functionDescriptor).setReturnType(getDefaultType());
}
}
@NotNull
@Override
public JetScope getMemberScope(List<TypeProjection> typeArguments) {
......@@ -164,7 +172,10 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
@NotNull
@Override
public JetType getDefaultType() {
return TypeUtils.makeUnsubstitutedType(this, scopeForMemberLookup);
if (defaultType == null) {
defaultType = TypeUtils.makeUnsubstitutedType(this, scopeForMemberLookup);
}
return defaultType;
}
@NotNull
......@@ -226,6 +237,6 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
@Override
public String toString() {
return DescriptorRenderer.TEXT.render(this) + "[" + getClass().getCanonicalName() + "@" + System.identityHashCode(this) + "]";
return DescriptorRenderer.TEXT_FOR_DEBUG.render(this) + "[" + getClass().getCanonicalName() + "@" + System.identityHashCode(this) + "]";
}
}
......@@ -2,6 +2,7 @@ package org.jetbrains.jet.lang.descriptors;
import com.google.common.collect.Sets;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetTupleType;
import org.jetbrains.jet.lang.resolve.JetScope;
import org.jetbrains.jet.lang.resolve.LazyScopeAdapter;
import org.jetbrains.jet.lang.types.*;
......@@ -68,7 +69,7 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement
}
public void addUpperBound(@NotNull JetType bound) {
upperBounds.add(bound);
upperBounds.add(bound); // TODO : Duplicates?
}
public Set<JetType> getUpperBounds() {
......@@ -93,7 +94,7 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement
assert upperBounds.size() > 0;
boundsAsType = TypeUtils.intersect(JetTypeChecker.INSTANCE, upperBounds);
if (boundsAsType == null) {
boundsAsType = JetStandardClasses.getNothingType(); // TODO : some error message?
boundsAsType = JetStandardClasses.getNothingType();
}
}
return boundsAsType;
......@@ -145,6 +146,10 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement
return true;
}
public void addClassObjectBound(@NotNull JetType bound) {
classObjectUpperBounds.add(bound); // TODO : Duplicates?
}
public int getIndex() {
return index;
}
......
......@@ -1170,20 +1170,25 @@ public class JetParsing extends AbstractJetParsing {
/*
* typeConstraint
* : userType ":" type
* : "class" "object" userType ":" type
* : attributes SimpleName ":" type
* : attributes "class" "object" SimpleName ":" type
* ;
*/
private void parseTypeConstraint() {
PsiBuilder.Marker constraint = mark();
parseAttributeList();
if (at(CLASS_KEYWORD)) {
advance(); // CLASS_KEYWORD
expect(OBJECT_KEYWORD, "Expecting 'object'", TYPE_REF_FIRST);
}
parseTypeRef();
PsiBuilder.Marker reference = mark();
expect(IDENTIFIER, "Expecting type parameter name", TokenSet.orSet(TokenSet.create(COLON, COMMA), TYPE_REF_FIRST));
reference.done(REFERENCE_EXPRESSION);
expect(COLON, "Expecting ':' before the upper bound", TYPE_REF_FIRST);
......
......@@ -26,20 +26,12 @@ public class JetTypeConstraint extends JetElement {
}
@Nullable @IfNotParsed
public JetTypeReference getSubjectTypeReference() {
ASTNode node = getNode().getFirstChildNode();
while (node != null) {
IElementType tt = node.getElementType();
if (tt == JetTokens.COLON) break;
if (tt == JetNodeTypes.TYPE_REFERENCE) return (JetTypeReference) node.getPsi();
node = node.getTreeNext();
}
return null;
public JetSimpleNameExpression getSubjectTypeParameterName() {
return (JetSimpleNameExpression) findChildByType(JetNodeTypes.REFERENCE_EXPRESSION);
}
@Nullable @IfNotParsed
public JetTypeReference getExtendsTypeReference() {
public JetTypeReference getBoundTypeReference() {
boolean passedColon = false;
ASTNode node = getNode().getFirstChildNode();
while (node != null) {
......
......@@ -21,6 +21,19 @@ public class JetTypeParameterListOwner extends JetNamedDeclaration {
return (JetTypeParameterList) findChildByType(JetNodeTypes.TYPE_PARAMETER_LIST);
}
@NotNull
public List<JetTypeConstraint> getTypeConstaints() {
JetTypeParameterList typeParameterList = getTypeParameterList();
if (typeParameterList == null) {
return Collections.emptyList();
}
JetTypeConstraintList typeConstraintList = typeParameterList.getTypeConstraintList();
if (typeConstraintList == null) {
return Collections.emptyList();
}
return typeConstraintList.getConstraints();
}
@NotNull
public List<JetTypeParameter> getTypeParameters() {
JetTypeParameterList list = getTypeParameterList();
......
package org.jetbrains.jet.lang.resolve;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.JetSemanticServices;
......@@ -134,9 +136,11 @@ public class ClassDescriptorResolver {
public void resolveGenericBounds(@NotNull JetClass jetClass, @NotNull MutableClassDescriptor classDescriptor) {
List<JetTypeParameter> typeParameters = jetClass.getTypeParameters();
List<TypeParameterDescriptor> parameters = classDescriptor.getTypeConstructor().getParameters();
Map<String, TypeParameterDescriptor> parameterByName = Maps.newHashMap();
for (int i = 0, typeParametersSize = typeParameters.size(); i < typeParametersSize; i++) {
JetTypeParameter jetTypeParameter = typeParameters.get(i);
TypeParameterDescriptor typeParameterDescriptor = parameters.get(i);
parameterByName.put(typeParameterDescriptor.getName(), typeParameterDescriptor);
JetTypeReference extendsBound = jetTypeParameter.getExtendsBound();
if (extendsBound != null) {
typeParameterDescriptor.addUpperBound(typeResolverNotCheckingBounds.resolveType(classDescriptor.getScopeForSupertypeResolution(), extendsBound));
......@@ -145,7 +149,48 @@ public class ClassDescriptorResolver {
typeParameterDescriptor.addUpperBound(JetStandardClasses.getDefaultBound());
}
}
// TODO : Bounds from with
for (JetTypeConstraint constraint : jetClass.getTypeConstaints()) {
JetSimpleNameExpression subjectTypeParameterName = constraint.getSubjectTypeParameterName();
if (subjectTypeParameterName == null) {
continue;
}
String referencedName = subjectTypeParameterName.getReferencedName();
if (referencedName == null) {
continue;
}
TypeParameterDescriptor typeParameterDescriptor = parameterByName.get(referencedName);
if (typeParameterDescriptor == null) {
// To tell the user that we look only for locally defined type parameters
ClassifierDescriptor classifier = classDescriptor.getScopeForSupertypeResolution().getClassifier(referencedName);
if (classifier != null) {
trace.getErrorHandler().genericError(subjectTypeParameterName.getNode(), referencedName + " does not refer to a type parameter of class " + classDescriptor.getName());
trace.recordReferenceResolution(subjectTypeParameterName, classifier);
}
else {
trace.getErrorHandler().unresolvedReference(subjectTypeParameterName);
}
}
else {
JetTypeReference boundTypeReference = constraint.getBoundTypeReference();
if (boundTypeReference != null) {
JetType bound = typeResolverNotCheckingBounds.resolveType(classDescriptor.getScopeForSupertypeResolution(), boundTypeReference);
if (constraint.isClassObjectContraint()) {
typeParameterDescriptor.addClassObjectBound(bound);
}
else {
typeParameterDescriptor.addUpperBound(bound);
}
}
}
}
for (TypeParameterDescriptor parameter : parameters) {
if (JetStandardClasses.isNothing(parameter.getBoundsAsType())) {
PsiElement nameIdentifier = typeParameters.get(parameter.getIndex()).getNameIdentifier();
if (nameIdentifier != null) {
trace.getErrorHandler().genericError(nameIdentifier.getNode(), "Upper bounds of " + parameter.getName() + " have empty intersection");
}
}
}
}
public void resolveSupertypes(@NotNull JetClassOrObject jetClass, @NotNull MutableClassDescriptor descriptor) {
......
......@@ -17,6 +17,11 @@ public interface JetScope {
public DeclarationDescriptor getContainingDeclaration() {
throw new UnsupportedOperationException(); // TODO
}
@Override
public String toString() {
return "EMPTY";
}
};
@Nullable
......
......@@ -298,6 +298,11 @@ public class TopDownAnalyzer {
JetClass jetClass = entry.getKey();
MutableClassDescriptor descriptor = entry.getValue();
classDescriptorResolver.resolveMutableClassDescriptor(jetClass, descriptor);
descriptor.createTypeConstructor();
}
for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> entry : objects.entrySet()) {
MutableClassDescriptor descriptor = entry.getValue();
descriptor.createTypeConstructor();
}
}
......@@ -439,8 +444,6 @@ public class TopDownAnalyzer {
checkIfPrimaryConstructorIsNecessary();
bindOverrides();
checkGenericBoundsInClassHeaders();
}
private void bindOverrides() {
......
......@@ -64,8 +64,7 @@ public class TypeResolver {
typeParameterDescriptor.getTypeConstructor(),
nullable || TypeUtils.hasNullableBound(typeParameterDescriptor),
Collections.<TypeProjection>emptyList(),
// TODO : joint domain
JetStandardClasses.STUB
getScopeForTypeParameter(typeParameterDescriptor)
);
}
else if (classifierDescriptor instanceof ClassDescriptor) {
......@@ -160,6 +159,20 @@ public class TypeResolver {
return result[0];
}
private JetScope getScopeForTypeParameter(final TypeParameterDescriptor typeParameterDescriptor) {
if (checkBounds) {
return typeParameterDescriptor.getBoundsAsType().getMemberScope();
}
else {
return new LazyScopeAdapter(new LazyValue<JetScope>() {
@Override
protected JetScope compute() {
return typeParameterDescriptor.getBoundsAsType().getMemberScope();
}
});
}
}
private List<JetType> resolveTypes(JetScope scope, List<JetTypeReference> argumentElements) {
final List<JetType> arguments = new ArrayList<JetType>();
for (JetTypeReference argumentElement : argumentElements) {
......
......@@ -117,6 +117,7 @@ public class JavaDescriptorResolver {
Collections.<Annotation>emptyList(),
false);
constructorDescriptor.initialize(Collections.<ValueParameterDescriptor>emptyList());
constructorDescriptor.setReturnType(classDescriptor.getDefaultType());
classDescriptor.addConstructor(constructorDescriptor);
semanticServices.getTrace().recordDeclarationResolution(psiClass, constructorDescriptor);
}
......@@ -128,12 +129,14 @@ public class JavaDescriptorResolver {
Collections.<Annotation>emptyList(), // TODO
false);
constructorDescriptor.initialize(resolveParameterDescriptors(constructorDescriptor, constructor.getParameterList().getParameters()));
constructorDescriptor.setReturnType(classDescriptor.getDefaultType());
classDescriptor.addConstructor(constructorDescriptor);
semanticServices.getTrace().recordDeclarationResolution(constructor, constructorDescriptor);
}
}
semanticServices.getTrace().recordDeclarationResolution(psiClass, classDescriptor);
return classDescriptor;
}
......
......@@ -5,6 +5,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.ErrorHandler;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.resolve.JetScope;
import org.jetbrains.jet.lang.resolve.JetScopeImpl;
import org.jetbrains.jet.lang.resolve.WritableScope;
import org.jetbrains.jet.lang.resolve.WritableScopeImpl;
......@@ -74,7 +75,18 @@ public class JetStandardClasses {
null
);
private static final JetType ANY_TYPE = new JetTypeImpl(ANY.getTypeConstructor(), JetScope.EMPTY);
private static final JetType ANY_TYPE = new JetTypeImpl(ANY.getTypeConstructor(), new JetScopeImpl() {
@NotNull
@Override
public DeclarationDescriptor getContainingDeclaration() {
return STANDARD_CLASSES_NAMESPACE;
}
@Override
public String toString() {
return "Scope for Any";
}
});
private static final JetType NULLABLE_ANY_TYPE = TypeUtils.makeNullable(ANY_TYPE);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
......
......@@ -138,7 +138,7 @@ public class JetTypeChecker {
}
// TODO : attributes?
return new JetTypeImpl(Collections.<Annotation>emptyList(), constructor, nullable, newProjections, JetStandardClasses.STUB);
return new JetTypeImpl(Collections.<Annotation>emptyList(), constructor, nullable, newProjections, JetStandardClasses.STUB); // TODO : scope
}
@NotNull
......
......@@ -640,6 +640,11 @@ public class JetTypeInferrer {
}
try {
expression.accept(this);
// Some recursive definitions (object expressions) must put their types in the cache manually:
if (trace.isProcessed(expression)) {
return trace.getBindingContext().getExpressionType(expression);
}
if (result instanceof DeferredType) {
result = ((DeferredType) result).getActualType();
}
......@@ -754,9 +759,14 @@ public class JetTypeInferrer {
public void visitObjectLiteralExpression(final JetObjectLiteralExpression expression) {
TopDownAnalyzer topDownAnalyzer = new TopDownAnalyzer(semanticServices, new BindingTraceAdapter(trace) {
@Override
public void recordDeclarationResolution(@NotNull PsiElement declaration, @NotNull DeclarationDescriptor descriptor) {
public void recordDeclarationResolution(@NotNull PsiElement declaration, @NotNull final DeclarationDescriptor descriptor) {
if (declaration == expression.getObjectDeclaration()) {
JetType defaultType = ((ClassDescriptor) descriptor).getDefaultType();
JetType defaultType = new DeferredType(new LazyValue<JetType>() {
@Override
protected JetType compute() {
return ((ClassDescriptor) descriptor).getDefaultType();
}
});
result = defaultType;
if (!trace.isProcessed(expression)) {
recordExpressionType(expression, defaultType);
......
......@@ -8,6 +8,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.Annotation;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.resolve.ChainedScope;
import org.jetbrains.jet.lang.resolve.JetScope;
import java.util.*;
......@@ -70,13 +71,27 @@ public class TypeUtils {
}
List<Annotation> noAnnotations = Collections.<Annotation>emptyList();
TypeConstructor constructor = new TypeConstructorImpl(null, noAnnotations, false, debugName.toString(), Collections.<TypeParameterDescriptor>emptyList(), types);
TypeConstructor constructor = new TypeConstructorImpl(
null,
noAnnotations,
false,
debugName.toString(),
Collections.<TypeParameterDescriptor>emptyList(),
types);
JetScope[] scopes = new JetScope[types.size()];
int i = 0;
for (JetType type : types) {
scopes[i] = type.getMemberScope();
i++;
}
return new JetTypeImpl(
noAnnotations,
constructor,
nullable,
Collections.<TypeProjection>emptyList(),
JetStandardClasses.STUB);
new ChainedScope(null, scopes)); // TODO : check intersectibility, don't use a chanied scope
}
private static boolean canHaveSubtypes(JetTypeChecker typeChecker, JetType type) {
......@@ -176,7 +191,7 @@ public class TypeUtils {
private static List<TypeProjection> getArguments(@NotNull ClassDescriptor classDescriptor) {
List<TypeProjection> result = new ArrayList<TypeProjection>();
for (TypeParameterDescriptor parameterDescriptor : classDescriptor.getTypeConstructor().getParameters()) {
result.add(new TypeProjection(new JetTypeImpl(parameterDescriptor.getTypeConstructor(), JetScope.EMPTY))); // TODO : scope?
result.add(new TypeProjection(parameterDescriptor.getDefaultType()));
}
return result;
}
......
......@@ -274,7 +274,7 @@ public class DescriptorRenderer {
renderName(descriptor, builder);
if (!descriptor.getUpperBounds().isEmpty()) {
JetType bound = descriptor.getUpperBounds().iterator().next();
if (bound != JetStandardClasses.getAnyType()) {
if (bound != JetStandardClasses.getDefaultBound()) {
builder.append(" : ").append(renderType(bound));
if (descriptor.getUpperBounds().size() > 1) {
builder.append(" (...)");
......
......@@ -14,10 +14,8 @@ JetFile: TypeConstraints.jet
PsiWhiteSpace(' ')
TYPE_CONSTRAINT_LIST
TYPE_CONSTRAINT
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('T')
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('T')
PsiWhiteSpace(' ')
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
......@@ -32,10 +30,8 @@ JetFile: TypeConstraints.jet
PsiWhiteSpace(' ')
PsiElement(object)('object')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('T')
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('T')
PsiWhiteSpace(' ')
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
......
......@@ -213,10 +213,8 @@ JetFile: PolymorphicClassObjects.jet
PsiWhiteSpace('\n ')
TYPE_CONSTRAINT_LIST
TYPE_CONSTRAINT
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('T')
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('T')
PsiWhiteSpace(' ')
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
......@@ -239,10 +237,8 @@ JetFile: PolymorphicClassObjects.jet
PsiWhiteSpace(' ')
PsiElement(object)('object')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('T')
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('T')
PsiWhiteSpace(' ')
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册