Array access as LValue resolution fixed
This commit is contained in:
@@ -1478,6 +1478,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final PsiElement declaration = BindingContextUtils.resolveToDeclarationPsiElement(bindingContext, expression);
|
final PsiElement declaration = BindingContextUtils.resolveToDeclarationPsiElement(bindingContext, expression);
|
||||||
|
assert declaration != null : "No declaration found for " + expression.getText();
|
||||||
final CallableMethod accessor;
|
final CallableMethod accessor;
|
||||||
if (declaration instanceof PsiMethod) {
|
if (declaration instanceof PsiMethod) {
|
||||||
accessor = JetTypeMapper.mapToCallableMethod((PsiMethod) declaration);
|
accessor = JetTypeMapper.mapToCallableMethod((PsiMethod) declaration);
|
||||||
@@ -1486,7 +1487,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
accessor = typeMapper.mapToCallableMethod((JetNamedFunction) declaration);
|
accessor = typeMapper.mapToCallableMethod((JetNamedFunction) declaration);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new UnsupportedOperationException("unknown accessor type");
|
throw new UnsupportedOperationException("unknown accessor type: " + declaration);
|
||||||
}
|
}
|
||||||
boolean isGetter = accessor.getSignature().getName().equals("get");
|
boolean isGetter = accessor.getSignature().getName().equals("get");
|
||||||
return StackValue.collectionElement(JetTypeMapper.TYPE_OBJECT, isGetter ? accessor : null,
|
return StackValue.collectionElement(JetTypeMapper.TYPE_OBJECT, isGetter ? accessor : null,
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package org.jetbrains.jet.lang;
|
||||||
|
|
||||||
|
import com.intellij.lang.ASTNode;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||||
|
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
|
||||||
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author abreslav
|
||||||
|
*/
|
||||||
|
public class CompositeErrorHandler extends ErrorHandler {
|
||||||
|
private final ErrorHandler[] handlers;
|
||||||
|
|
||||||
|
public CompositeErrorHandler(ErrorHandler... handlers) {
|
||||||
|
this.handlers = handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unresolvedReference(@NotNull JetReferenceExpression referenceExpression) {
|
||||||
|
for (ErrorHandler handler : handlers) {
|
||||||
|
handler.unresolvedReference(referenceExpression);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void typeMismatch(@NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull JetType actualType) {
|
||||||
|
for (ErrorHandler handler : handlers) {
|
||||||
|
handler.typeMismatch(expression, expectedType, actualType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void redeclaration(@NotNull DeclarationDescriptor existingDescriptor, @NotNull DeclarationDescriptor redeclaredDescriptor) {
|
||||||
|
for (ErrorHandler handler : handlers) {
|
||||||
|
handler.redeclaration(existingDescriptor, redeclaredDescriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void genericError(@NotNull ASTNode node, @NotNull String errorMessage) {
|
||||||
|
for (ErrorHandler handler : handlers) {
|
||||||
|
handler.genericError(node, errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void genericWarning(@NotNull ASTNode node, @NotNull String message) {
|
||||||
|
for (ErrorHandler handler : handlers) {
|
||||||
|
handler.genericWarning(node, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,8 @@ import com.intellij.psi.tree.IElementType;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.JetNodeTypes;
|
import org.jetbrains.jet.JetNodeTypes;
|
||||||
|
import org.jetbrains.jet.lang.CompositeErrorHandler;
|
||||||
|
import org.jetbrains.jet.lang.ErrorHandler;
|
||||||
import org.jetbrains.jet.lang.JetSemanticServices;
|
import org.jetbrains.jet.lang.JetSemanticServices;
|
||||||
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
|
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
@@ -228,7 +230,7 @@ public class JetTypeInferrer {
|
|||||||
expectedReturnType = NO_EXPECTED_TYPE;
|
expectedReturnType = NO_EXPECTED_TYPE;
|
||||||
}
|
}
|
||||||
JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(outerScope, functionDescriptor, trace);
|
JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(outerScope, functionDescriptor, trace);
|
||||||
checkFunctionReturnType(functionInnerScope, function, expectedReturnType, dataFlowInfo);
|
checkFunctionReturnType(functionInnerScope, function, expectedReturnType, dataFlowInfo, CoercionStrategy.NO_COERCION);
|
||||||
// Map<JetElement, JetType> typeMap = collectReturnedExpressionsWithTypes(outerScope, function, functionDescriptor, expectedReturnType);
|
// Map<JetElement, JetType> typeMap = collectReturnedExpressionsWithTypes(outerScope, function, functionDescriptor, expectedReturnType);
|
||||||
// if (typeMap.isEmpty()) {
|
// if (typeMap.isEmpty()) {
|
||||||
// return; // The function returns Nothing
|
// return; // The function returns Nothing
|
||||||
@@ -263,10 +265,10 @@ public class JetTypeInferrer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void checkFunctionReturnType(JetScope functionInnerScope, JetDeclarationWithBody function, @NotNull final JetType expectedReturnType) {
|
public void checkFunctionReturnType(JetScope functionInnerScope, JetDeclarationWithBody function, @NotNull final JetType expectedReturnType) {
|
||||||
checkFunctionReturnType(functionInnerScope, function, expectedReturnType, DataFlowInfo.getEmpty());
|
checkFunctionReturnType(functionInnerScope, function, expectedReturnType, DataFlowInfo.getEmpty(), CoercionStrategy.NO_COERCION);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkFunctionReturnType(JetScope functionInnerScope, JetDeclarationWithBody function, @NotNull final JetType expectedReturnType, @NotNull DataFlowInfo dataFlowInfo) {
|
private void checkFunctionReturnType(JetScope functionInnerScope, JetDeclarationWithBody function, @NotNull final JetType expectedReturnType, @NotNull DataFlowInfo dataFlowInfo, CoercionStrategy coercionForLastExpression) {
|
||||||
JetExpression bodyExpression = function.getBodyExpression();
|
JetExpression bodyExpression = function.getBodyExpression();
|
||||||
assert bodyExpression != null;
|
assert bodyExpression != null;
|
||||||
|
|
||||||
@@ -276,7 +278,13 @@ public class JetTypeInferrer {
|
|||||||
? new TypeInferenceContext(trace, functionInnerScope, function.hasBlockBody(), dataFlowInfo, NO_EXPECTED_TYPE, expectedReturnType)
|
? new TypeInferenceContext(trace, functionInnerScope, function.hasBlockBody(), dataFlowInfo, NO_EXPECTED_TYPE, expectedReturnType)
|
||||||
: new TypeInferenceContext(trace, functionInnerScope, function.hasBlockBody(), dataFlowInfo, expectedReturnType, FORBIDDEN);
|
: new TypeInferenceContext(trace, functionInnerScope, function.hasBlockBody(), dataFlowInfo, expectedReturnType, FORBIDDEN);
|
||||||
|
|
||||||
typeInferrerVisitor.getType(bodyExpression, context);
|
if (function instanceof JetFunctionLiteralExpression) {
|
||||||
|
JetFunctionLiteralExpression functionLiteralExpression = (JetFunctionLiteralExpression) function;
|
||||||
|
getBlockReturnedType(functionInnerScope, functionLiteralExpression.getBodyExpression(), CoercionStrategy.COERCION_TO_UNIT, context);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
typeInferrerVisitor.getType(bodyExpression, context);
|
||||||
|
}
|
||||||
|
|
||||||
List<JetElement> unreachableElements = Lists.newArrayList();
|
List<JetElement> unreachableElements = Lists.newArrayList();
|
||||||
flowInformationProvider.collectUnreachableExpressions(function.asElement(), unreachableElements);
|
flowInformationProvider.collectUnreachableExpressions(function.asElement(), unreachableElements);
|
||||||
@@ -326,6 +334,18 @@ public class JetTypeInferrer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private JetType getBlockReturnedType(@NotNull JetScope outerScope, @NotNull JetBlockExpression expression, @NotNull CoercionStrategy coercionStrategyForLastExpression, TypeInferenceContext context) {
|
||||||
|
List<JetElement> block = expression.getStatements();
|
||||||
|
if (block.isEmpty()) {
|
||||||
|
return checkType(JetStandardClasses.getUnitType(), expression, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
DeclarationDescriptor containingDescriptor = outerScope.getContainingDeclaration();
|
||||||
|
WritableScope scope = new WritableScopeImpl(outerScope, containingDescriptor, context.trace.getErrorHandler()).setDebugName("getBlockReturnedType");
|
||||||
|
return getBlockReturnedTypeWithWritableScope(scope, block, coercionStrategyForLastExpression, context);
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public JetType inferFunctionReturnType(@NotNull JetScope outerScope, JetDeclarationWithBody function, FunctionDescriptor functionDescriptor) {
|
public JetType inferFunctionReturnType(@NotNull JetScope outerScope, JetDeclarationWithBody function, FunctionDescriptor functionDescriptor) {
|
||||||
Map<JetElement, JetType> typeMap = collectReturnedExpressionsWithTypes(trace, outerScope, function, functionDescriptor);
|
Map<JetElement, JetType> typeMap = collectReturnedExpressionsWithTypes(trace, outerScope, function, functionDescriptor);
|
||||||
@@ -361,7 +381,7 @@ public class JetTypeInferrer {
|
|||||||
return typeMap;
|
return typeMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
private JetType getBlockReturnedTypeWithWritableScope(@NotNull WritableScope scope, @NotNull List<? extends JetElement> block, TypeInferenceContext context) {
|
private JetType getBlockReturnedTypeWithWritableScope(@NotNull WritableScope scope, @NotNull List<? extends JetElement> block, @NotNull CoercionStrategy coercionStrategyForLastExpression, TypeInferenceContext context) {
|
||||||
if (block.isEmpty()) {
|
if (block.isEmpty()) {
|
||||||
return JetStandardClasses.getUnitType();
|
return JetStandardClasses.getUnitType();
|
||||||
}
|
}
|
||||||
@@ -371,15 +391,42 @@ public class JetTypeInferrer {
|
|||||||
|
|
||||||
JetType result = null;
|
JetType result = null;
|
||||||
for (Iterator<? extends JetElement> iterator = block.iterator(); iterator.hasNext(); ) {
|
for (Iterator<? extends JetElement> iterator = block.iterator(); iterator.hasNext(); ) {
|
||||||
JetElement statement = iterator.next();
|
final JetElement statement = iterator.next();
|
||||||
trace.record(STATEMENT, statement);
|
trace.record(STATEMENT, statement);
|
||||||
JetExpression statementExpression = (JetExpression) statement;
|
final JetExpression statementExpression = (JetExpression) statement;
|
||||||
//TODO constructor assert context.expectedType != FORBIDDEN : ""
|
//TODO constructor assert context.expectedType != FORBIDDEN : ""
|
||||||
if (!iterator.hasNext() && context.expectedType != NO_EXPECTED_TYPE) {
|
if (!iterator.hasNext() && context.expectedType != NO_EXPECTED_TYPE) {
|
||||||
newContext = new TypeInferenceContext(trace, scope, true, newContext.dataFlowInfo, context.expectedType, context.expectedReturnType);
|
if (coercionStrategyForLastExpression == CoercionStrategy.COERCION_TO_UNIT && JetStandardClasses.isUnit(context.expectedType)) {
|
||||||
|
// This implements coercion to Unit
|
||||||
|
TemporaryBindingTrace temporaryTraceExpectingUnit = TemporaryBindingTrace.create(trace);
|
||||||
|
final boolean[] mismatch = new boolean[1];
|
||||||
|
BindingTraceAdapter errorInterceptingTrace = makeTraceInterceptingTypeMismatch(temporaryTraceExpectingUnit, statementExpression, mismatch);
|
||||||
|
newContext = new TypeInferenceContext(errorInterceptingTrace, scope, true, newContext.dataFlowInfo, context.expectedType, context.expectedReturnType);
|
||||||
|
result = blockLevelVisitor.getType(statementExpression, newContext);
|
||||||
|
if (mismatch[0]) {
|
||||||
|
TemporaryBindingTrace temporaryTraceNoExpectedType = TemporaryBindingTrace.create(trace);
|
||||||
|
mismatch[0] = false;
|
||||||
|
BindingTraceAdapter interceptingTrace = makeTraceInterceptingTypeMismatch(temporaryTraceNoExpectedType, statementExpression, mismatch);
|
||||||
|
newContext = new TypeInferenceContext(interceptingTrace, scope, true, newContext.dataFlowInfo, NO_EXPECTED_TYPE, context.expectedReturnType);
|
||||||
|
result = blockLevelVisitor.getType(statementExpression, newContext);
|
||||||
|
if (mismatch[0]) {
|
||||||
|
temporaryTraceExpectingUnit.commit();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
temporaryTraceNoExpectedType.commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
newContext = new TypeInferenceContext(trace, scope, true, newContext.dataFlowInfo, context.expectedType, context.expectedReturnType);
|
||||||
|
result = blockLevelVisitor.getType(statementExpression, newContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = blockLevelVisitor.getType(statementExpression, newContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = blockLevelVisitor.getType(statementExpression, newContext);
|
|
||||||
DataFlowInfo newDataFlowInfo = blockLevelVisitor.getResultingDataFlowInfo();
|
DataFlowInfo newDataFlowInfo = blockLevelVisitor.getResultingDataFlowInfo();
|
||||||
if (newDataFlowInfo == null) {
|
if (newDataFlowInfo == null) {
|
||||||
newDataFlowInfo = context.dataFlowInfo;
|
newDataFlowInfo = context.dataFlowInfo;
|
||||||
@@ -392,6 +439,23 @@ public class JetTypeInferrer {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BindingTraceAdapter makeTraceInterceptingTypeMismatch(final BindingTrace trace, JetExpression expression, final boolean[] mismatchFound) {
|
||||||
|
return new BindingTraceAdapter(trace) {
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public ErrorHandler getErrorHandler() {
|
||||||
|
return new CompositeErrorHandler(super.getErrorHandler(), new ErrorHandler() {
|
||||||
|
@Override
|
||||||
|
public void typeMismatch(@NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull JetType actualType) {
|
||||||
|
if (expression == expression) {
|
||||||
|
mismatchFound[0] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
//TODO
|
//TODO
|
||||||
private JetType enrichOutType(JetExpression expression, JetType initialType, @NotNull TypeInferenceContext context) {
|
private JetType enrichOutType(JetExpression expression, JetType initialType, @NotNull TypeInferenceContext context) {
|
||||||
if (expression == null) return initialType;
|
if (expression == null) return initialType;
|
||||||
@@ -482,17 +546,22 @@ public class JetTypeInferrer {
|
|||||||
}
|
}
|
||||||
return variableDescriptor;
|
return variableDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
private enum CoercionStrategy {
|
||||||
|
NO_COERCION,
|
||||||
|
COERCION_TO_UNIT
|
||||||
|
}
|
||||||
|
|
||||||
private class TypeInferenceContext {
|
private class TypeInferenceContext {
|
||||||
public final BindingTrace trace;
|
public final BindingTrace trace;
|
||||||
|
|
||||||
public final TypeResolver typeResolver;
|
public final TypeResolver typeResolver;
|
||||||
public final ClassDescriptorResolver classDescriptorResolver;
|
public final ClassDescriptorResolver classDescriptorResolver;
|
||||||
|
|
||||||
public final JetScope scope;
|
public final JetScope scope;
|
||||||
|
|
||||||
public final Services services;
|
public final Services services;
|
||||||
public final boolean preferBlock;
|
public final boolean preferBlock;
|
||||||
public final DataFlowInfo dataFlowInfo;
|
public final DataFlowInfo dataFlowInfo;
|
||||||
@@ -516,7 +585,6 @@ public class JetTypeInferrer {
|
|||||||
this.dataFlowInfo = dataFlowInfo;
|
this.dataFlowInfo = dataFlowInfo;
|
||||||
this.expectedType = expectedType;
|
this.expectedType = expectedType;
|
||||||
this.expectedReturnType = expectedReturnType;
|
this.expectedReturnType = expectedReturnType;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TypeInferenceContext replaceDataFlowInfo(DataFlowInfo newDataFlowInfo) {
|
public TypeInferenceContext replaceDataFlowInfo(DataFlowInfo newDataFlowInfo) {
|
||||||
@@ -612,18 +680,6 @@ public class JetTypeInferrer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private JetType getBlockReturnedType(@NotNull JetScope outerScope, @NotNull JetBlockExpression expression, TypeInferenceContext context) {
|
|
||||||
List<JetElement> block = expression.getStatements();
|
|
||||||
if (block.isEmpty()) {
|
|
||||||
return context.services.checkType(JetStandardClasses.getUnitType(), expression, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
DeclarationDescriptor containingDescriptor = outerScope.getContainingDeclaration();
|
|
||||||
WritableScope scope = new WritableScopeImpl(outerScope, containingDescriptor, context.trace.getErrorHandler()).setDebugName("getBlockReturnedType");
|
|
||||||
return context.services.getBlockReturnedTypeWithWritableScope(scope, block, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -742,7 +798,7 @@ public class JetTypeInferrer {
|
|||||||
JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
|
JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
|
||||||
if (context.preferBlock && !functionLiteral.hasParameterSpecification()) {
|
if (context.preferBlock && !functionLiteral.hasParameterSpecification()) {
|
||||||
context.trace.record(BindingContext.BLOCK, expression);
|
context.trace.record(BindingContext.BLOCK, expression);
|
||||||
return context.services.checkType(getBlockReturnedType(context.scope, functionLiteral.getBodyExpression(), context), expression, context);
|
return context.services.checkType(context.services.getBlockReturnedType(context.scope, functionLiteral.getBodyExpression(), CoercionStrategy.NO_COERCION, context), expression, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
JetTypeReference receiverTypeRef = functionLiteral.getReceiverTypeRef();
|
JetTypeReference receiverTypeRef = functionLiteral.getReceiverTypeRef();
|
||||||
@@ -809,18 +865,22 @@ public class JetTypeInferrer {
|
|||||||
JetTypeReference returnTypeRef = functionLiteral.getReturnTypeRef();
|
JetTypeReference returnTypeRef = functionLiteral.getReturnTypeRef();
|
||||||
if (returnTypeRef != null) {
|
if (returnTypeRef != null) {
|
||||||
returnType = context.typeResolver.resolveType(context.scope, returnTypeRef);
|
returnType = context.typeResolver.resolveType(context.scope, returnTypeRef);
|
||||||
context.services.checkFunctionReturnType(functionInnerScope, expression, returnType, context.dataFlowInfo);
|
context.services.checkFunctionReturnType(functionInnerScope, expression, returnType, context.dataFlowInfo, CoercionStrategy.COERCION_TO_UNIT);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (functionTypeExpected) {
|
if (functionTypeExpected) {
|
||||||
returnType = JetStandardClasses.getReturnType(expectedType);
|
returnType = JetStandardClasses.getReturnType(expectedType);
|
||||||
}
|
}
|
||||||
returnType = getBlockReturnedType(functionInnerScope, functionLiteral.getBodyExpression(), context.replaceExpectedType(returnType));
|
returnType = context.services.getBlockReturnedType(functionInnerScope, functionLiteral.getBodyExpression(), CoercionStrategy.COERCION_TO_UNIT, context.replaceExpectedType(returnType));
|
||||||
}
|
}
|
||||||
JetType safeReturnType = returnType == null ? ErrorUtils.createErrorType("<return type>") : returnType;
|
JetType safeReturnType = returnType == null ? ErrorUtils.createErrorType("<return type>") : returnType;
|
||||||
functionDescriptor.setReturnType(safeReturnType);
|
functionDescriptor.setReturnType(safeReturnType);
|
||||||
|
|
||||||
if (functionTypeExpected) {
|
if (functionTypeExpected) {
|
||||||
|
JetType expectedReturnType = JetStandardClasses.getReturnType(expectedType);
|
||||||
|
if (JetStandardClasses.isUnit(expectedReturnType)) {
|
||||||
|
return context.services.checkType(JetStandardClasses.getFunctionType(Collections.<AnnotationDescriptor>emptyList(), effectiveReceiverType, parameterTypes, expectedReturnType), expression, context);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return context.services.checkType(JetStandardClasses.getFunctionType(Collections.<AnnotationDescriptor>emptyList(), effectiveReceiverType, parameterTypes, safeReturnType), expression, context);
|
return context.services.checkType(JetStandardClasses.getFunctionType(Collections.<AnnotationDescriptor>emptyList(), effectiveReceiverType, parameterTypes, safeReturnType), expression, context);
|
||||||
@@ -1082,7 +1142,7 @@ public class JetTypeInferrer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JetType visitBlockExpression(JetBlockExpression expression, TypeInferenceContext context) {
|
public JetType visitBlockExpression(JetBlockExpression expression, TypeInferenceContext context) {
|
||||||
return context.services.checkType(getBlockReturnedType(context.scope, expression, context), expression, context);
|
return context.services.checkType(context.services.getBlockReturnedType(context.scope, expression, CoercionStrategy.NO_COERCION, context), expression, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1561,7 +1621,7 @@ public class JetTypeInferrer {
|
|||||||
if (!function.getFunctionLiteral().hasParameterSpecification()) {
|
if (!function.getFunctionLiteral().hasParameterSpecification()) {
|
||||||
WritableScope writableScope = newWritableScopeImpl(context.scope, context.trace).setDebugName("do..while body scope");
|
WritableScope writableScope = newWritableScopeImpl(context.scope, context.trace).setDebugName("do..while body scope");
|
||||||
conditionScope = writableScope;
|
conditionScope = writableScope;
|
||||||
context.services.getBlockReturnedTypeWithWritableScope(writableScope, function.getFunctionLiteral().getBodyExpression().getStatements(), context);
|
context.services.getBlockReturnedTypeWithWritableScope(writableScope, function.getFunctionLiteral().getBodyExpression().getStatements(), CoercionStrategy.NO_COERCION, context);
|
||||||
context.trace.record(BindingContext.BLOCK, function);
|
context.trace.record(BindingContext.BLOCK, function);
|
||||||
} else {
|
} else {
|
||||||
getType(context.scope, body, true, context);
|
getType(context.scope, body, true, context);
|
||||||
@@ -1570,7 +1630,7 @@ public class JetTypeInferrer {
|
|||||||
else if (body != null) {
|
else if (body != null) {
|
||||||
WritableScope writableScope = newWritableScopeImpl(context.scope, context.trace).setDebugName("do..while body scope");
|
WritableScope writableScope = newWritableScopeImpl(context.scope, context.trace).setDebugName("do..while body scope");
|
||||||
conditionScope = writableScope;
|
conditionScope = writableScope;
|
||||||
context.services.getBlockReturnedTypeWithWritableScope(writableScope, Collections.singletonList(body), context);
|
context.services.getBlockReturnedTypeWithWritableScope(writableScope, Collections.singletonList(body), CoercionStrategy.NO_COERCION, context);
|
||||||
}
|
}
|
||||||
JetExpression condition = expression.getCondition();
|
JetExpression condition = expression.getCondition();
|
||||||
checkCondition(conditionScope, condition, context);
|
checkCondition(conditionScope, condition, context);
|
||||||
@@ -2368,14 +2428,15 @@ public class JetTypeInferrer {
|
|||||||
// context.services.callResolver.resolveCallWithGivenName(
|
// context.services.callResolver.resolveCallWithGivenName(
|
||||||
// scope,
|
// scope,
|
||||||
// call,
|
// call,
|
||||||
// operationSign,
|
// arrayAccessExpression,
|
||||||
// "set", arrayAccessExpression.getArrayExpression(), NO_EXPECTED_TYPE);
|
// "set", arrayAccessExpression.getArrayExpression(), NO_EXPECTED_TYPE);
|
||||||
FunctionDescriptor functionDescriptor = context.services.callResolver.resolveCallWithGivenName(
|
FunctionDescriptor functionDescriptor = context.services.callResolver.resolveCallWithGivenName(
|
||||||
scope,
|
scope,
|
||||||
call,
|
call,
|
||||||
operationSign,
|
arrayAccessExpression,
|
||||||
"set", receiverType, NO_EXPECTED_TYPE);
|
"set", receiverType, NO_EXPECTED_TYPE);
|
||||||
if (functionDescriptor == null) return null;
|
if (functionDescriptor == null) return null;
|
||||||
|
context.trace.record(REFERENCE_TARGET, operationSign, functionDescriptor);
|
||||||
return context.services.checkType(functionDescriptor.getReturnType(), arrayAccessExpression, context);
|
return context.services.checkType(functionDescriptor.getReturnType(), arrayAccessExpression, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,4 +42,9 @@ public final class ManyMapKey<K, V> {
|
|||||||
result = 31 * result + (key != null ? key.hashCode() : 0);
|
result = 31 * result + (key != null ? key.hashCode() : 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return slice + " -> " + key;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,121 @@
|
|||||||
|
import java.util.*
|
||||||
|
|
||||||
|
namespace html {
|
||||||
|
|
||||||
|
abstract class Factory<T> {
|
||||||
|
fun create() : T
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class Element
|
||||||
|
|
||||||
|
class TextElement(val text : String) : Element
|
||||||
|
|
||||||
|
abstract class Tag(val name : String) : Element {
|
||||||
|
val children = ArrayList<Element>()
|
||||||
|
val attributes = HashMap<String, String>()
|
||||||
|
|
||||||
|
protected fun initTag<T : Element>(init : fun T.() : Unit) : T
|
||||||
|
where class object T : Factory<T>{
|
||||||
|
val tag = T.create()
|
||||||
|
tag.init()
|
||||||
|
children.add(tag)
|
||||||
|
return tag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class TagWithText(name : String) : Tag(name) {
|
||||||
|
fun String.plus() {
|
||||||
|
children.add(TextElement(this))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class HTML() : TagWithText("html") {
|
||||||
|
class object : Factory<HTML> {
|
||||||
|
override fun create() = HTML()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun head(init : fun Head.() : Unit) = initTag<Head>(init)
|
||||||
|
|
||||||
|
fun body(init : fun Body.() : Unit) = initTag<Body>(init)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Head() : TagWithText("head") {
|
||||||
|
class object : Factory<Head> {
|
||||||
|
override fun create() = Head()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun title(init : fun Title.() : Unit) = initTag<Title>(init)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Title() : TagWithText("title")
|
||||||
|
|
||||||
|
class BodyTag(name : String) : TagWithText(name) {
|
||||||
|
}
|
||||||
|
|
||||||
|
class Body() : BodyTag("body") {
|
||||||
|
class object : Factory<Body> {
|
||||||
|
override fun create() = Body()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun b(init : fun B.() : Unit) = initTag<B>(init)
|
||||||
|
fun p(init : fun P.() : Unit) = initTag<P>(init)
|
||||||
|
fun h1(init : fun H1.() : Unit) = initTag<H1>(init)
|
||||||
|
fun a(href : String, init : fun A.() : Unit) {
|
||||||
|
val a = initTag<A>(init)
|
||||||
|
a.href = href
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B() : BodyTag("b")
|
||||||
|
class P() : BodyTag("p")
|
||||||
|
class H1() : BodyTag("h1")
|
||||||
|
class A() : BodyTag("a") {
|
||||||
|
var href : String
|
||||||
|
get() = attributes["href"]
|
||||||
|
set(value) { attributes["href"] = value }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Map<String, String>.set(key : String, value : String) = this.put(key, value)
|
||||||
|
|
||||||
|
fun html(init : fun HTML.() : Unit) : HTML {
|
||||||
|
val html = HTML()
|
||||||
|
html.init()
|
||||||
|
return html
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace foo {
|
||||||
|
|
||||||
|
import html.*
|
||||||
|
|
||||||
|
fun result(args : Array<String>) =
|
||||||
|
html {
|
||||||
|
head {
|
||||||
|
title {+"XML encoding with Groovy"}
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
h1 {+"XML encoding with Groovy"}
|
||||||
|
p {+"this format can be used as an alternative markup to XML"}
|
||||||
|
|
||||||
|
// an element with attributes and text content
|
||||||
|
a(href = "http://groovy.codehaus.org") {+"Groovy"}
|
||||||
|
|
||||||
|
// mixed content
|
||||||
|
p {
|
||||||
|
+"This is some"
|
||||||
|
b {+"mixed"}
|
||||||
|
+"text. For more see the"
|
||||||
|
a(href = "http://groovy.codehaus.org") {+"Groovy"}
|
||||||
|
+"project"
|
||||||
|
}
|
||||||
|
p {+"some text"}
|
||||||
|
|
||||||
|
// content generated by
|
||||||
|
p {
|
||||||
|
for (arg in args)
|
||||||
|
+arg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user