Property accessors checked. Many things TBD

This commit is contained in:
Andrey Breslav
2011-04-18 22:31:59 +04:00
parent ec080358cb
commit 78f3eac62a
25 changed files with 492 additions and 175 deletions
+2
View File
@@ -88,10 +88,12 @@ property
;
getter
: modifiers "get"
: modifiers "get" "(" ")" (":" type)? functionBody
;
setter
: modifiers "set"
: modifiers "set" "(" modifiers (SimpleName | parameter) ")" functionBody
;
@@ -761,7 +761,7 @@ public class JetParsing extends AbstractJetParsing {
}
/*
* getter
* getterOrSetter
* : modifiers ("get" | "set")
* :
* ( "get" "(" ")"
@@ -791,6 +791,7 @@ public class JetParsing extends AbstractJetParsing {
myBuilder.disableNewlines();
expect(LPAR, "Expecting '('", TokenSet.create(RPAR, IDENTIFIER, COLON, LBRACE, EQ));
if (setter) {
PsiBuilder.Marker parameterList = mark();
PsiBuilder.Marker setterParameter = mark();
int lastId = findLastBefore(TokenSet.create(IDENTIFIER), TokenSet.create(RPAR, COMMA, COLON), false);
createTruncatedBuilder(lastId).parseModifierList();
@@ -802,6 +803,7 @@ public class JetParsing extends AbstractJetParsing {
parseTypeRef();
}
setterParameter.done(VALUE_PARAMETER);
parameterList.done(VALUE_PARAMETER_LIST);
}
if (!at(RPAR)) errorUntil("Expecting ')'", TokenSet.create(RPAR, COLON, LBRACE, EQ, EOL_OR_SEMICOLON));
expect(RPAR, "Expecting ')'", TokenSet.create(RPAR, COLON, LBRACE, EQ));
@@ -4,6 +4,7 @@ import com.intellij.lang.ASTNode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.Collections;
import java.util.List;
@@ -47,4 +48,15 @@ public class JetConstructor extends JetDeclaration implements JetDeclarationWith
public JetExpression getBodyExpression() {
return findChildByClass(JetExpression.class);
}
@Override
public boolean hasBlockBody() {
return findChildByType(JetTokens.EQ) == null;
}
@NotNull
@Override
public JetElement asElement() {
return this;
}
}
@@ -1,5 +1,7 @@
package org.jetbrains.jet.lang.psi;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
@@ -12,5 +14,10 @@ public interface JetDeclarationWithBody {
@Nullable
String getName();
boolean hasBlockBody();
@NotNull
JetElement asElement();
}
@@ -41,7 +41,6 @@ public class JetFunction extends JetTypeParameterListOwner implements JetDeclara
return findChildByClass(JetExpression.class);
}
@Nullable
public JetTypeReference getReceiverTypeRef() {
PsiElement child = getFirstChild();
@@ -75,7 +74,14 @@ public class JetFunction extends JetTypeParameterListOwner implements JetDeclara
return null;
}
@Override
public boolean hasBlockBody() {
return findChildByType(JetTokens.EQ) == null;
}
@NotNull
@Override
public JetElement asElement() {
return this;
}
}
@@ -86,6 +86,7 @@ public class JetProperty extends JetNamedDeclaration {
return null;
}
@Nullable
public JetExpression getInitializer() {
PsiElement eq = findChildByType(JetTokens.EQ);
return PsiTreeUtil.getNextSiblingOfType(eq, JetExpression.class);
@@ -6,10 +6,12 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.List;
/**
* @author max
*/
public class JetPropertyAccessor extends JetDeclaration {
public class JetPropertyAccessor extends JetDeclaration implements JetDeclarationWithBody {
public JetPropertyAccessor(@NotNull ASTNode node) {
super(node);
}
@@ -29,11 +31,32 @@ public class JetPropertyAccessor extends JetDeclaration {
@Nullable
public JetParameter getParameter() {
return (JetParameter) findChildByType(JetNodeTypes.VALUE_PARAMETER);
JetParameterList parameterList = (JetParameterList) findChildByType(JetNodeTypes.VALUE_PARAMETER_LIST);
if (parameterList == null) return null;
List<JetParameter> parameters = parameterList.getParameters();
if (parameters.isEmpty()) return null;
return parameters.get(0);
}
@Nullable
public JetExpression getBody() {
@Override
public JetExpression getBodyExpression() {
return findChildByClass(JetExpression.class);
}
@Override
public boolean hasBlockBody() {
return findChildByType(JetTokens.EQ) == null;
}
@NotNull
@Override
public JetElement asElement() {
return this;
}
@Nullable
public JetTypeReference getReturnTypeReference() {
return findChildByClass(JetTypeReference.class);
}
}
@@ -185,7 +185,8 @@ public class ClassDescriptorResolver {
return functionDescriptor;
}
private List<ValueParameterDescriptor> resolveValueParameters(FunctionDescriptorImpl functionDescriptor, WritableScope parameterScope, List<JetParameter> valueParameters) {
@NotNull
private List<ValueParameterDescriptor> resolveValueParameters(MutableFunctionDescriptor functionDescriptor, WritableScope parameterScope, List<JetParameter> valueParameters) {
List<ValueParameterDescriptor> result = new ArrayList<ValueParameterDescriptor>();
for (int i = 0, valueParametersSize = valueParameters.size(); i < valueParametersSize; i++) {
JetParameter valueParameter = valueParameters.get(i);
@@ -203,25 +204,32 @@ public class ClassDescriptorResolver {
} else {
type = typeResolver.resolveType(parameterScope, typeReference);
}
ValueParameterDescriptor valueParameterDescriptor = new ValueParameterDescriptorImpl(
functionDescriptor,
i,
AttributeResolver.INSTANCE.resolveAttributes(valueParameter.getModifierList()),
JetPsiUtil.safeName(valueParameter.getName()),
valueParameter.isMutable() ? type : null,
type,
valueParameter.getDefaultValue() != null,
false // TODO : varargs
);
// TODO : Default values???
result.add(valueParameterDescriptor);
trace.recordDeclarationResolution(valueParameter, valueParameterDescriptor);
ValueParameterDescriptor valueParameterDescriptor = resolveValueParameterDescriptor(functionDescriptor, valueParameter, i, type);
parameterScope.addVariableDescriptor(valueParameterDescriptor);
result.add(valueParameterDescriptor);
}
return result;
}
@NotNull
private MutableValueParameterDescriptor resolveValueParameterDescriptor(DeclarationDescriptor declarationDescriptor, JetParameter valueParameter, int index, JetType type) {
MutableValueParameterDescriptor valueParameterDescriptor = new ValueParameterDescriptorImpl(
declarationDescriptor,
index,
AttributeResolver.INSTANCE.resolveAttributes(valueParameter.getModifierList()),
JetPsiUtil.safeName(valueParameter.getName()),
valueParameter.isMutable() ? type : null,
type,
valueParameter.getDefaultValue() != null,
false // TODO : varargs
);
// TODO : Default values???
trace.recordDeclarationResolution(valueParameter, valueParameterDescriptor);
return valueParameterDescriptor;
}
public List<TypeParameterDescriptor> resolveTypeParameters(DeclarationDescriptor containingDescriptor, WritableScope extensibleScope, List<JetTypeParameter> typeParameters) {
// TODO : Where-clause
List<TypeParameterDescriptor> result = new ArrayList<TypeParameterDescriptor>();
@@ -269,11 +277,11 @@ public class ClassDescriptorResolver {
@NotNull
public VariableDescriptor resolveLocalVariableDescriptor(@NotNull DeclarationDescriptor containingDeclaration, @NotNull JetScope scope, @NotNull JetParameter parameter) {
JetType type = getParameterType(scope, parameter);
JetType type = resolveParameterType(scope, parameter);
return resolveLocalVariableDescriptor(containingDeclaration, parameter, type);
}
private JetType getParameterType(JetScope scope, JetParameter parameter) {
private JetType resolveParameterType(JetScope scope, JetParameter parameter) {
JetTypeReference typeReference = parameter.getTypeReference();
JetType type;
if (typeReference != null) {
@@ -310,19 +318,93 @@ public class ClassDescriptorResolver {
return propertyDescriptor;
}
public VariableDescriptor resolvePropertyDescriptor(@NotNull DeclarationDescriptor containingDeclaration, @NotNull JetScope scope, JetProperty property) {
public PropertyDescriptor resolvePropertyDescriptor(@NotNull DeclarationDescriptor containingDeclaration, @NotNull JetScope scope, JetProperty property) {
JetType type = getType(scope, property);
VariableDescriptorImpl propertyDescriptor = new PropertyDescriptor(
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(
containingDeclaration,
AttributeResolver.INSTANCE.resolveAttributes(property.getModifierList()),
JetPsiUtil.safeName(property.getName()),
property.isVar() ? type : null,
type);
propertyDescriptor.initialize(
resolvePropertyGetterDescriptor(scope, property, propertyDescriptor),
resolvePropertySetterDescriptors(scope, property, propertyDescriptor));
trace.recordDeclarationResolution(property, propertyDescriptor);
return propertyDescriptor;
}
@Nullable
private PropertySetterDescriptor resolvePropertySetterDescriptors(@NotNull JetScope scope, @NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor) {
JetPropertyAccessor setter = property.getSetter();
if (setter != null && !property.isVar()) {
semanticServices.getErrorHandler().genericError(setter.asElement().getNode(), "A 'val'-property cannot have a setter");
return null;
}
PropertySetterDescriptor setterDescriptor = null;
if (setter != null) {
List<Attribute> attributes = AttributeResolver.INSTANCE.resolveAttributes(setter.getModifierList());
JetParameter parameter = setter.getParameter();
setterDescriptor = new PropertySetterDescriptor(propertyDescriptor, attributes);
if (parameter != null) {
if (parameter.isRef()) {
semanticServices.getErrorHandler().genericError(parameter.getRefNode(), "Setter parameters can not be 'ref'");
}
// This check is redundant: the parser does not allow a default value, but we'll keep it just in case
JetExpression defaultValue = parameter.getDefaultValue();
if (defaultValue != null) {
semanticServices.getErrorHandler().genericError(defaultValue.getNode(), "Setter parameters can not have default values");
}
JetType type;
JetTypeReference typeReference = parameter.getTypeReference();
if (typeReference == null) {
type = propertyDescriptor.getInType(); // TODO : this maybe unknown at this point
}
else {
type = typeResolver.resolveType(scope, typeReference);
JetType inType = propertyDescriptor.getInType();
if (inType != null) {
if (!semanticServices.getTypeChecker().isSubtypeOf(type, inType)) {
semanticServices.getErrorHandler().genericError(typeReference.getNode(), "Setter parameter type must be a subtype of the type of the property, i.e. " + inType);
}
}
else {
// TODO : the same check may be needed later???
}
}
MutableValueParameterDescriptor valueParameterDescriptor = resolveValueParameterDescriptor(setterDescriptor, parameter, 0, type);
setterDescriptor.initialize(valueParameterDescriptor);
}
trace.recordDeclarationResolution(setter, setterDescriptor);
}
return setterDescriptor;
}
@Nullable
private PropertyGetterDescriptor resolvePropertyGetterDescriptor(@NotNull JetScope scope, @NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor) {
PropertyGetterDescriptor getterDescriptor = null;
JetPropertyAccessor getter = property.getGetter();
if (getter != null) {
List<Attribute> attributes = AttributeResolver.INSTANCE.resolveAttributes(getter.getModifierList());
JetType returnType = null;
JetTypeReference returnTypeReference = getter.getReturnTypeReference();
if (returnTypeReference != null) {
returnType = typeResolver.resolveType(scope, returnTypeReference);
}
getterDescriptor = new PropertyGetterDescriptor(propertyDescriptor, attributes, returnType);
trace.recordDeclarationResolution(getter, getterDescriptor);
}
return getterDescriptor;
}
@NotNull
private JetType getType(@NotNull JetScope scope, @NotNull JetProperty property) {
// TODO : receiver?
@@ -336,7 +418,7 @@ public class ClassDescriptorResolver {
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).getType(scope, initializer, false);
type = semanticServices.getTypeInferrer(trace, JetFlowInformationProvider.THROW_EXCEPTION).safeGetType(scope, initializer, false);
}
} else {
type = typeResolver.resolveType(scope, propertyTypeRef);
@@ -395,7 +477,7 @@ public class ClassDescriptorResolver {
@NotNull ClassDescriptor classDescriptor,
@NotNull JetScope scope,
@NotNull JetParameter parameter) {
JetType type = getParameterType(scope, parameter);
JetType type = resolveParameterType(scope, parameter);
String name = parameter.getName();
VariableDescriptorImpl propertyDescriptor = new PropertyDescriptor(
classDescriptor,
@@ -18,6 +18,7 @@ public class TopDownAnalyzer {
private final Map<JetClass, MutableClassDescriptor> classes = new LinkedHashMap<JetClass, MutableClassDescriptor>();
private final Map<JetNamespace, WritableScope> namespaceScopes = new LinkedHashMap<JetNamespace, WritableScope>();
private final Map<JetDeclaration, FunctionDescriptor> functions = new LinkedHashMap<JetDeclaration, FunctionDescriptor>();
private final Map<JetProperty, PropertyDescriptor> properties = new LinkedHashMap<JetProperty, PropertyDescriptor>();
private final Map<JetDeclaration, WritableScope> declaringScopes = new HashMap<JetDeclaration, WritableScope>();
private final JetSemanticServices semanticServices;
@@ -240,8 +241,9 @@ public class TopDownAnalyzer {
private void processProperty(WritableScope declaringScope, JetProperty property) {
declaringScopes.put(property, declaringScope);
VariableDescriptor descriptor = classDescriptorResolver.resolvePropertyDescriptor(declaringScope.getContainingDeclaration(), declaringScope, property);
PropertyDescriptor descriptor = classDescriptorResolver.resolvePropertyDescriptor(declaringScope.getContainingDeclaration(), declaringScope, property);
declaringScope.addVariableDescriptor(descriptor);
properties.put(property, descriptor);
}
private void processClassObject(JetClassObject classObject) {
@@ -258,52 +260,13 @@ public class TopDownAnalyzer {
WritableScope declaringScope = declaringScopes.get(declaration);
assert declaringScope != null;
assert declaration instanceof JetFunction || declaration instanceof JetConstructor;
JetDeclarationWithBody declarationWithBody = (JetDeclarationWithBody) declaration;
JetExpression bodyExpression = declarationWithBody.getBodyExpression();
if (declaration instanceof JetFunction) {
JetFunction function = (JetFunction) declaration;
FunctionDescriptorImpl functionDescriptorImpl = (FunctionDescriptorImpl) descriptor;
if (bodyExpression != null) {
JetFlowInformationProvider flowInformationProvider = computeFlowData(function, bodyExpression);
JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(trace, flowInformationProvider);
assert readyToProcessExpressions : "Must be ready collecting types";
if (function.getReturnTypeRef() != null) {
typeInferrer.checkFunctionReturnType(declaringScope, function, functionDescriptorImpl);
}
else {
JetType returnType = typeInferrer.getFunctionReturnType(declaringScope, function, functionDescriptorImpl);
if (returnType == null) {
returnType = ErrorUtils.createErrorType("Unable to infer body type");
}
functionDescriptorImpl.setUnsubstitutedReturnType(returnType);
}
List<JetElement> unreachableElements = new ArrayList<JetElement>();
flowInformationProvider.collectUnreachableExpressions(function, unreachableElements);
// This is needed in order to highlight only '1 < 2' and not '1', '<' and '2' as well
Set<JetElement> rootElements = JetPsiUtil.findRootExpressions(unreachableElements);
// TODO : (return 1) || (return 2) -- only || and right of it is unreachable
// TODO : try {return 1} finally {return 2}. Currently 'return 1' is reported as unreachable,
// though it'd better be reported more specifically
for (JetElement element : rootElements) {
semanticServices.getErrorHandler().genericError(element.getNode(), "Unreachable code");
}
}
else {
if (function.getReturnTypeRef() == null) {
semanticServices.getErrorHandler().genericError(function.getNode(), "This function must either declare a return type or have a body element");
((FunctionDescriptorImpl) descriptor).setUnsubstitutedReturnType(ErrorUtils.createErrorType("No type, no body"));
}
}
resolveFunctionBody((JetFunction) declaration, (FunctionDescriptorImpl) descriptor, declaringScope);
}
else if (declaration instanceof JetConstructor) {
if (bodyExpression != null) {
@@ -316,9 +279,77 @@ public class TopDownAnalyzer {
}
assert descriptor.getUnsubstitutedReturnType() != null;
}
for (Map.Entry<JetProperty, PropertyDescriptor> entry : properties.entrySet()) {
JetProperty declaration = entry.getKey();
PropertyDescriptor descriptor = entry.getValue();
WritableScope declaringScope = declaringScopes.get(declaration);
JetExpression initializer = declaration.getInitializer();
if (initializer != null) {
JetFlowInformationProvider flowInformationProvider = computeFlowData(declaration, initializer);
JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(trace, flowInformationProvider);
JetType type = typeInferrer.getType(declaringScope, initializer, false);
// TODO : check type
}
JetPropertyAccessor getter = declaration.getGetter();
PropertyGetterDescriptor getterDescriptor = descriptor.getGetter();
if (getter != null && getterDescriptor != null) {
resolveFunctionBody(getter, getterDescriptor, declaringScope);
}
JetPropertyAccessor setter = declaration.getSetter();
PropertySetterDescriptor setterDescriptor = descriptor.getSetter();
if (setter != null && setterDescriptor != null) {
resolveFunctionBody(setter, setterDescriptor, declaringScope);
}
}
}
private JetFlowInformationProvider computeFlowData(@NotNull JetDeclaration declaration, @NotNull JetExpression bodyExpression) {
private void resolveFunctionBody(@NotNull JetDeclarationWithBody function, @NotNull MutableFunctionDescriptor functionDescriptor, @NotNull WritableScope declaringScope) {
JetExpression bodyExpression = function.getBodyExpression();
if (bodyExpression != null) {
JetFlowInformationProvider flowInformationProvider = computeFlowData(function.asElement(), bodyExpression);
JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(trace, flowInformationProvider);
assert readyToProcessExpressions : "Must be ready collecting types";
if (functionDescriptor.isReturnTypeSet()) {
typeInferrer.checkFunctionReturnType(declaringScope, function, functionDescriptor);
}
else {
JetType returnType = typeInferrer.getFunctionReturnType(declaringScope, function, functionDescriptor);
if (returnType == null) {
returnType = ErrorUtils.createErrorType("Unable to infer body type");
}
functionDescriptor.setUnsubstitutedReturnType(returnType);
}
List<JetElement> unreachableElements = new ArrayList<JetElement>();
flowInformationProvider.collectUnreachableExpressions(function.asElement(), unreachableElements);
// This is needed in order to highlight only '1 < 2' and not '1', '<' and '2' as well
Set<JetElement> rootElements = JetPsiUtil.findRootExpressions(unreachableElements);
// TODO : (return 1) || (return 2) -- only || and right of it is unreachable
// TODO : try {return 1} finally {return 2}. Currently 'return 1' is reported as unreachable,
// though it'd better be reported more specifically
for (JetElement element : rootElements) {
semanticServices.getErrorHandler().genericError(element.getNode(), "Unreachable code");
}
}
else {
if (!functionDescriptor.isReturnTypeSet()) {
semanticServices.getErrorHandler().genericError(function.asElement().getNode(), "This function must either declare a return type or have a body element");
functionDescriptor.setUnsubstitutedReturnType(ErrorUtils.createErrorType("No type, no body"));
}
}
}
private JetFlowInformationProvider computeFlowData(@NotNull JetElement declaration, @NotNull JetExpression bodyExpression) {
final JetPseudocodeTrace pseudocodeTrace = flowDataTraceFactory.createTrace(declaration);
final Map<JetElement, Pseudocode> pseudocodeMap = new HashMap<JetElement, Pseudocode>();
final Map<JetElement, Instruction> representativeInstructions = new HashMap<JetElement, Instruction>();
@@ -43,4 +43,16 @@ public class DeclarationDescriptorVisitor<R, D> {
public R visitValueParameterDescriptor(ValueParameterDescriptor descriptor, D data) {
return visitVariableDescriptor(descriptor, data);
}
public R visitPropertyGetterDescriptor(PropertyGetterDescriptor descriptor, D data) {
return visitPropertyAccessorDescriptor(descriptor, data);
}
private R visitPropertyAccessorDescriptor(PropertyAccessorDescriptor descriptor, D data) {
return visitFunctionDescriptor(descriptor, data);
}
public R visitPropertySetterDescriptor(PropertySetterDescriptor descriptor, D data) {
return visitPropertyAccessorDescriptor(descriptor, data);
}
}
@@ -8,7 +8,7 @@ import java.util.List;
/**
* @author abreslav
*/
public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements FunctionDescriptor {
public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements MutableFunctionDescriptor {
private List<TypeParameterDescriptor> typeParameters;
@@ -43,10 +43,16 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements
return this;
}
@Override
public void setUnsubstitutedReturnType(@NotNull JetType unsubstitutedReturnType) {
this.unsubstitutedReturnType = unsubstitutedReturnType;
}
@Override
public boolean isReturnTypeSet() {
return unsubstitutedReturnType != null;
}
@Override
@NotNull
public List<TypeParameterDescriptor> getTypeParameters() {
@@ -269,7 +269,7 @@ public class JetTypeInferrer {
}
@NotNull
public JetType getFunctionReturnType(@NotNull JetScope outerScope, JetFunction function, FunctionDescriptor functionDescriptor) {
public JetType getFunctionReturnType(@NotNull JetScope outerScope, JetDeclarationWithBody function, FunctionDescriptor functionDescriptor) {
Map<JetElement, JetType> typeMap = collectReturnedExpressions(outerScope, function, functionDescriptor);
Collection<JetType> types = typeMap.values();
return types.isEmpty() ? JetStandardClasses.getNothingType() : semanticServices.getTypeChecker().commonSupertype(types);
@@ -280,7 +280,7 @@ public class JetTypeInferrer {
return typeCache.get(expression);
}
public void checkFunctionReturnType(@NotNull JetScope outerScope, @NotNull JetFunction function, @NotNull FunctionDescriptor functionDescriptor) {
public void checkFunctionReturnType(@NotNull JetScope outerScope, @NotNull JetDeclarationWithBody function, @NotNull FunctionDescriptor functionDescriptor) {
Map<JetElement, JetType> typeMap = collectReturnedExpressions(outerScope, function, functionDescriptor);
if (typeMap.isEmpty()) {
return; // The function returns Nothing
@@ -292,8 +292,8 @@ public class JetTypeInferrer {
JetTypeChecker typeChecker = semanticServices.getTypeChecker();
if (!typeChecker.isSubtypeOf(actualType, expectedReturnType)) {
if (typeChecker.isConvertibleBySpecialConversion(actualType, expectedReturnType)) {
if (expectedReturnType.getConstructor().equals(JetStandardClasses.getUnitType().getConstructor()) &&
element.getParent() instanceof JetReturnExpression) {
if (expectedReturnType.getConstructor().equals(JetStandardClasses.getUnitType().getConstructor())
&& element.getParent() instanceof JetReturnExpression) {
semanticServices.getErrorHandler().genericError(element.getNode(), "This function must return a value of type Unit");
}
}
@@ -315,14 +315,14 @@ public class JetTypeInferrer {
}
}
private Map<JetElement, JetType> collectReturnedExpressions(JetScope outerScope, JetFunction function, FunctionDescriptor functionDescriptor) {
private Map<JetElement, JetType> collectReturnedExpressions(JetScope outerScope, JetDeclarationWithBody function, FunctionDescriptor functionDescriptor) {
JetExpression bodyExpression = function.getBodyExpression();
assert bodyExpression != null;
JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(outerScope, functionDescriptor, semanticServices);
getType(functionInnerScope, bodyExpression, function.hasBlockBody());
Collection<JetExpression> returnedExpressions = new ArrayList<JetExpression>();
Collection<JetElement> elementsReturningUnit = new ArrayList<JetElement>();
flowInformationProvider.collectReturnedInformation(function, returnedExpressions, elementsReturningUnit);
flowInformationProvider.collectReturnedInformation(function.asElement(), returnedExpressions, elementsReturningUnit);
Map<JetElement,JetType> typeMap = new HashMap<JetElement, JetType>();
for (JetExpression returnedExpression : returnedExpressions) {
JetType cachedType = getCachedType(returnedExpression);
@@ -0,0 +1,12 @@
package org.jetbrains.jet.lang.types;
import org.jetbrains.annotations.NotNull;
/**
* @author abreslav
*/
public interface MutableFunctionDescriptor extends FunctionDescriptor {
void setUnsubstitutedReturnType(@NotNull JetType type);
boolean isReturnTypeSet();
}
@@ -0,0 +1,10 @@
package org.jetbrains.jet.lang.types;
import org.jetbrains.annotations.NotNull;
/**
* @author abreslav
*/
public interface MutableValueParameterDescriptor extends ValueParameterDescriptor {
void setType(@NotNull JetType type);
}
@@ -8,40 +8,10 @@ import java.util.List;
/**
* @author abreslav
*/
public class PropertyAccessorDescriptor extends DeclarationDescriptorImpl implements FunctionDescriptor {
public enum AccessorType {
GETTER("get"),
SETTER("set");
public abstract class PropertyAccessorDescriptor extends DeclarationDescriptorImpl implements FunctionDescriptor {
private final String name;
AccessorType(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public static PropertyAccessorDescriptor createGetterDescriptor(
@NotNull PropertyDescriptor correspondingProperty,
@NotNull List<Attribute> attributes,
@NotNull JetType returnType
) {
return new PropertyAccessorDescriptor(correspondingProperty, attributes, AccessorType.GETTER);
}
public static PropertyAccessorDescriptor createSetterDescriptor(
@NotNull PropertyDescriptor correspondingProperty,
@NotNull List<Attribute> attributes,
@NotNull ValueParameterDescriptor parameter
) {
return new PropertyAccessorDescriptor(correspondingProperty, attributes, AccessorType.SETTER);
}
protected PropertyAccessorDescriptor(@NotNull PropertyDescriptor correspondingProperty, @NotNull List<Attribute> attributes, @NotNull AccessorType accessorType) {
super(correspondingProperty.getContainingDeclaration(), attributes, accessorType.getName());
protected PropertyAccessorDescriptor(@NotNull PropertyDescriptor correspondingProperty, @NotNull List<Attribute> attributes, @NotNull String name) {
super(correspondingProperty.getContainingDeclaration(), attributes, name);
}
@NotNull
@@ -61,21 +31,4 @@ public class PropertyAccessorDescriptor extends DeclarationDescriptorImpl implem
public List<TypeParameterDescriptor> getTypeParameters() {
return Collections.emptyList();
}
@NotNull
@Override
public List<ValueParameterDescriptor> getUnsubstitutedValueParameters() {
throw new UnsupportedOperationException(); // TODO
}
@NotNull
@Override
public JetType getUnsubstitutedReturnType() {
throw new UnsupportedOperationException(); // TODO
}
@Override
public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
throw new UnsupportedOperationException(); // TODO
}
}
@@ -10,8 +10,8 @@ import java.util.List;
*/
public class PropertyDescriptor extends VariableDescriptorImpl {
private PropertyAccessorDescriptor getter;
private PropertyAccessorDescriptor setter;
private PropertyGetterDescriptor getter;
private PropertySetterDescriptor setter;
private boolean hasBackingField;
public PropertyDescriptor(
@@ -23,11 +23,18 @@ public class PropertyDescriptor extends VariableDescriptorImpl {
super(containingDeclaration, attributes, name, inType, outType);
}
public PropertyAccessorDescriptor getGetter() {
public void initialize(@Nullable PropertyGetterDescriptor getter, @Nullable PropertySetterDescriptor setter) {
this.getter = getter;
this.setter = setter;
}
@Nullable
public PropertyGetterDescriptor getGetter() {
return getter;
}
public PropertyAccessorDescriptor getSetter() {
@Nullable
public PropertySetterDescriptor getSetter() {
return setter;
}
@@ -0,0 +1,47 @@
package org.jetbrains.jet.lang.types;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
/**
* @author abreslav
*/
public class PropertyGetterDescriptor extends PropertyAccessorDescriptor implements MutableFunctionDescriptor {
private JetType returnType;
public PropertyGetterDescriptor(@NotNull PropertyDescriptor correspondingProperty, @NotNull List<Attribute> attributes, @Nullable JetType returnType) {
super(correspondingProperty, attributes, "get-" + correspondingProperty.getName());
this.returnType = returnType == null ? correspondingProperty.getOutType() : returnType;
}
@NotNull
@Override
public List<ValueParameterDescriptor> getUnsubstitutedValueParameters() {
return Collections.emptyList();
}
@NotNull
@Override
public JetType getUnsubstitutedReturnType() {
return returnType;
}
@Override
public void setUnsubstitutedReturnType(@NotNull JetType type) {
assert this.returnType == null : this.returnType;
this.returnType = type;
}
@Override
public boolean isReturnTypeSet() {
return returnType != null;
}
@Override
public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
return visitor.visitPropertyGetterDescriptor(this, data);
}
}
@@ -0,0 +1,54 @@
package org.jetbrains.jet.lang.types;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
/**
* @author abreslav
*/
public class PropertySetterDescriptor extends PropertyAccessorDescriptor implements MutableFunctionDescriptor {
private MutableValueParameterDescriptor parameter;
public PropertySetterDescriptor(@NotNull PropertyDescriptor correspondingProperty, @NotNull List<Attribute> attributes) {
super(correspondingProperty, attributes, "set-" + correspondingProperty.getName());
}
public void initialize(@NotNull MutableValueParameterDescriptor parameter) {
assert this.parameter == null;
this.parameter = parameter;
}
public void setParameterType(@NotNull JetType type) {
parameter.setType(type);
}
@NotNull
@Override
public List<ValueParameterDescriptor> getUnsubstitutedValueParameters() {
return Collections.<ValueParameterDescriptor>singletonList(parameter);
}
@NotNull
@Override
public JetType getUnsubstitutedReturnType() {
return JetStandardClasses.getUnitType();
}
@Override
public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
return visitor.visitPropertySetterDescriptor(this, data);
}
@Override
public void setUnsubstitutedReturnType(@NotNull JetType type) {
throw new UnsupportedOperationException("Can't set return type for a setter");
}
@Override
public boolean isReturnTypeSet() {
return true;
}
}
@@ -8,9 +8,10 @@ import java.util.List;
/**
* @author abreslav
*/
public class ValueParameterDescriptorImpl extends VariableDescriptorImpl implements ValueParameterDescriptor {
public class ValueParameterDescriptorImpl extends VariableDescriptorImpl implements MutableValueParameterDescriptor {
private final boolean hasDefaultValue;
private final boolean isVararg;
private final boolean isVar;
private final int index;
public ValueParameterDescriptorImpl(
@@ -26,6 +27,32 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme
this.index = index;
this.hasDefaultValue = hasDefaultValue;
this.isVararg = isVararg;
this.isVar = inType != null;
}
public ValueParameterDescriptorImpl(
@NotNull DeclarationDescriptor containingDeclaration,
int index,
@NotNull List<Attribute> attributes,
@NotNull String name,
boolean isVar,
boolean hasDefaultValue,
boolean isVararg) {
super(containingDeclaration, attributes, name, null, null);
this.index = index;
this.hasDefaultValue = hasDefaultValue;
this.isVararg = isVararg;
this.isVar = isVar;
}
@Override
public void setType(@NotNull JetType type) {
assert getOutType() == null;
setOutType(type);
if (isVar) {
assert getInType() == null;
setInType(type);
}
}
@Override
@@ -9,8 +9,8 @@ import java.util.List;
* @author abreslav
*/
public abstract class VariableDescriptorImpl extends DeclarationDescriptorImpl implements VariableDescriptor {
private final JetType inType;
private final JetType outType;
private JetType inType;
private JetType outType;
public VariableDescriptorImpl(
@NotNull DeclarationDescriptor containingDeclaration,
@@ -25,7 +25,6 @@ public abstract class VariableDescriptorImpl extends DeclarationDescriptorImpl i
this.outType = outType;
}
@NotNull
@Override
public JetType getOutType() {
return outType;
@@ -35,4 +34,12 @@ public abstract class VariableDescriptorImpl extends DeclarationDescriptorImpl i
public JetType getInType() {
return inType;
}
protected void setInType(JetType inType) {
this.inType = inType;
}
protected void setOutType(JetType outType) {
this.outType = outType;
}
}
+7 -1
View File
@@ -1 +1,7 @@
val x : Int
var x : Int = 1 + x
get() : Int = 1
set(<error>ref</error> value : <error>Long</error>) {$x = value}
val xx : Int = 1 + x
get() : Int = 1
<error>set(ref value : Long) {$x = value}</error>
+35 -28
View File
@@ -149,8 +149,9 @@ JetFile: Properties.jet
PROPERTY_ACCESSOR
PsiElement(set)('set')
PsiElement(LPAR)('(')
VALUE_PARAMETER
PsiElement(IDENTIFIER)('sad')
VALUE_PARAMETER_LIST
VALUE_PARAMETER
PsiElement(IDENTIFIER)('sad')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(EQ)('=')
@@ -204,8 +205,9 @@ JetFile: Properties.jet
PROPERTY_ACCESSOR
PsiElement(set)('set')
PsiElement(LPAR)('(')
VALUE_PARAMETER
PsiElement(IDENTIFIER)('it')
VALUE_PARAMETER_LIST
VALUE_PARAMETER
PsiElement(IDENTIFIER)('it')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
BLOCK
@@ -265,8 +267,9 @@ JetFile: Properties.jet
PROPERTY_ACCESSOR
PsiElement(set)('set')
PsiElement(LPAR)('(')
VALUE_PARAMETER
PsiElement(IDENTIFIER)('it')
VALUE_PARAMETER_LIST
VALUE_PARAMETER
PsiElement(IDENTIFIER)('it')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
BLOCK
@@ -341,15 +344,16 @@ JetFile: Properties.jet
PsiWhiteSpace(' ')
PsiElement(set)('set')
PsiElement(LPAR)('(')
VALUE_PARAMETER
PsiElement(IDENTIFIER)('a')
PsiWhiteSpace(' ')
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('b')
VALUE_PARAMETER_LIST
VALUE_PARAMETER
PsiElement(IDENTIFIER)('a')
PsiWhiteSpace(' ')
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('b')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
BLOCK
@@ -403,15 +407,16 @@ JetFile: Properties.jet
PsiWhiteSpace(' ')
PsiElement(set)('set')
PsiElement(LPAR)('(')
VALUE_PARAMETER
PsiElement(IDENTIFIER)('a')
PsiWhiteSpace(' ')
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('b')
VALUE_PARAMETER_LIST
VALUE_PARAMETER
PsiElement(IDENTIFIER)('a')
PsiWhiteSpace(' ')
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('b')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
BLOCK
@@ -548,8 +553,9 @@ JetFile: Properties.jet
PROPERTY_ACCESSOR
PsiElement(set)('set')
PsiElement(LPAR)('(')
VALUE_PARAMETER
PsiElement(IDENTIFIER)('sad')
VALUE_PARAMETER_LIST
VALUE_PARAMETER
PsiElement(IDENTIFIER)('sad')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(EQ)('=')
@@ -654,8 +660,9 @@ JetFile: Properties.jet
PROPERTY_ACCESSOR
PsiElement(set)('set')
PsiElement(LPAR)('(')
VALUE_PARAMETER
PsiElement(IDENTIFIER)('sad')
VALUE_PARAMETER_LIST
VALUE_PARAMETER
PsiElement(IDENTIFIER)('sad')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(EQ)('=')
+4 -3
View File
@@ -235,9 +235,10 @@ JetFile: Properties_ERR.jet
PROPERTY_ACCESSOR
PsiElement(set)('set')
PsiElement(LPAR)('(')
VALUE_PARAMETER
PsiErrorElement:Expecting parameter name
<empty list>
VALUE_PARAMETER_LIST
VALUE_PARAMETER
PsiErrorElement:Expecting parameter name
<empty list>
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
BLOCK
+10 -9
View File
@@ -292,15 +292,16 @@ JetFile: SoftKeywords.jet
PROPERTY_ACCESSOR
PsiElement(set)('set')
PsiElement(LPAR)('(')
VALUE_PARAMETER
PsiElement(IDENTIFIER)('S')
PsiWhiteSpace(' ')
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('s')
VALUE_PARAMETER_LIST
VALUE_PARAMETER
PsiElement(IDENTIFIER)('S')
PsiWhiteSpace(' ')
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('s')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
BLOCK
@@ -1081,8 +1081,9 @@ JetFile: BinaryHeap.jet
PROPERTY_ACCESSOR
PsiElement(set)('set')
PsiElement(LPAR)('(')
VALUE_PARAMETER
PsiElement(IDENTIFIER)('it')
VALUE_PARAMETER_LIST
VALUE_PARAMETER
PsiElement(IDENTIFIER)('it')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
BLOCK