@Override public JetTypeInfo visitObjectLiteralExpression( @NotNull final JetObjectLiteralExpression expression, final ExpressionTypingContext context) { DelegatingBindingTrace delegatingBindingTrace = context.trace.get(TRACE_DELTAS_CACHE, expression.getObjectDeclaration()); if (delegatingBindingTrace != null) { delegatingBindingTrace.addAllMyDataTo(context.trace); JetType type = context.trace.get(EXPRESSION_TYPE, expression); return DataFlowUtils.checkType(type, expression, context, context.dataFlowInfo); } final JetType[] result = new JetType[1]; final TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create( context.trace, "trace to resolve object literal expression", expression); ObservableBindingTrace.RecordHandler<PsiElement, ClassDescriptor> handler = new ObservableBindingTrace.RecordHandler<PsiElement, ClassDescriptor>() { @Override public void handleRecord( WritableSlice<PsiElement, ClassDescriptor> slice, PsiElement declaration, final ClassDescriptor descriptor) { if (slice == CLASS && declaration == expression.getObjectDeclaration()) { JetType defaultType = DeferredType.create( context.trace, createRecursionIntolerantLazyValueWithDefault( ErrorUtils.createErrorType("Recursive dependency"), new Function0<JetType>() { @Override public JetType invoke() { return descriptor.getDefaultType(); } })); result[0] = defaultType; if (!context.trace.get(PROCESSED, expression)) { temporaryTrace.record(EXPRESSION_TYPE, expression, defaultType); temporaryTrace.record(PROCESSED, expression); } } } }; ObservableBindingTrace traceAdapter = new ObservableBindingTrace(temporaryTrace); traceAdapter.addHandler(CLASS, handler); TopDownAnalyzer.processClassOrObject( context.replaceBindingTrace(traceAdapter).replaceContextDependency(INDEPENDENT), context.scope.getContainingDeclaration(), expression.getObjectDeclaration()); DelegatingBindingTrace cloneDelta = new DelegatingBindingTrace( new BindingTraceContext().getBindingContext(), "cached delta trace for object literal expression resolve", expression); temporaryTrace.addAllMyDataTo(cloneDelta); context.trace.record(TRACE_DELTAS_CACHE, expression.getObjectDeclaration(), cloneDelta); temporaryTrace.commit(); return DataFlowUtils.checkType(result[0], expression, context, context.dataFlowInfo); }
@NotNull protected JetTypeInfo visitAssignment( JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) { ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceScope(scope); JetExpression left = context.expressionTypingServices.deparenthesize(expression.getLeft(), context); JetExpression right = expression.getRight(); if (left instanceof JetArrayAccessExpression) { JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left; if (right == null) return JetTypeInfo.create(null, context.dataFlowInfo); JetTypeInfo typeInfo = basic.resolveArrayAccessSetMethod(arrayAccessExpression, right, context, context.trace); basic.checkLValue(context.trace, arrayAccessExpression); return JetTypeInfo.create( checkAssignmentType(typeInfo.getType(), expression, contextWithExpectedType), typeInfo.getDataFlowInfo()); } JetTypeInfo leftInfo = facade.getTypeInfo(expression.getLeft(), context); JetType leftType = leftInfo.getType(); DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo(); if (right != null) { JetTypeInfo rightInfo = facade.getTypeInfo( right, context.replaceDataFlowInfo(dataFlowInfo).replaceExpectedType(leftType)); dataFlowInfo = rightInfo.getDataFlowInfo(); } if (leftType != null) { // if leftType == null, some another error has been generated basic.checkLValue(context.trace, expression.getLeft()); } return DataFlowUtils.checkStatementType(expression, contextWithExpectedType, dataFlowInfo); }
@Nullable private JetType checkAssignmentType( @Nullable JetType assignmentType, @NotNull JetBinaryExpression expression, @NotNull ExpressionTypingContext context) { if (assignmentType != null && !KotlinBuiltIns.getInstance().isUnit(assignmentType) && context.expectedType != TypeUtils.NO_EXPECTED_TYPE && TypeUtils.equalTypes(context.expectedType, assignmentType)) { context.trace.report(Errors.ASSIGNMENT_TYPE_MISMATCH.on(expression, context.expectedType)); return null; } return DataFlowUtils.checkStatementType(expression, context); }
@Override public JetTypeInfo visitBinaryExpression( JetBinaryExpression expression, ExpressionTypingContext context) { JetSimpleNameExpression operationSign = expression.getOperationReference(); IElementType operationType = operationSign.getReferencedNameElementType(); JetTypeInfo result; if (operationType == JetTokens.EQ) { result = visitAssignment(expression, context); } else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) { result = visitAssignmentOperation(expression, context); } else { return facade.getTypeInfo(expression, context); } return DataFlowUtils.checkType(result.getType(), expression, context, result.getDataFlowInfo()); }
@Override public JetTypeInfo visitClass(JetClass klass, ExpressionTypingContext context) { TopDownAnalyzer.processClassOrObject( context.expressionTypingServices.getProject(), context.trace, scope, scope.getContainingDeclaration(), klass); ClassDescriptor classDescriptor = context.trace.getBindingContext().get(BindingContext.CLASS, klass); if (classDescriptor != null) { scope.addClassifierDescriptor(classDescriptor); } return DataFlowUtils.checkStatementType(klass, context, context.dataFlowInfo); }
@Override public JetTypeInfo visitFunctionLiteralExpression( @NotNull JetFunctionLiteralExpression expression, ExpressionTypingContext context) { JetBlockExpression bodyExpression = expression.getFunctionLiteral().getBodyExpression(); if (bodyExpression == null) return null; Name callerName = getCallerName(expression); if (callerName != null) { context.labelResolver.enterLabeledElement(new LabelName(callerName.asString()), expression); } JetType expectedType = context.expectedType; boolean functionTypeExpected = !noExpectedType(expectedType) && KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(expectedType); AnonymousFunctionDescriptor functionDescriptor = createFunctionDescriptor(expression, context, functionTypeExpected); JetType safeReturnType = computeReturnType(expression, context, functionDescriptor, functionTypeExpected); functionDescriptor.setReturnType(safeReturnType); JetType receiver = DescriptorUtils.getReceiverParameterType(functionDescriptor.getReceiverParameter()); List<JetType> valueParametersTypes = DescriptorUtils.getValueParametersTypes(functionDescriptor.getValueParameters()); JetType resultType = KotlinBuiltIns.getInstance() .getFunctionType( Collections.<AnnotationDescriptor>emptyList(), receiver, valueParametersTypes, safeReturnType); if (!noExpectedType(expectedType) && KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(expectedType)) { // all checks were done before return JetTypeInfo.create(resultType, context.dataFlowInfo); } if (callerName != null) { context.labelResolver.exitLabeledElement(expression); } return DataFlowUtils.checkType(resultType, expression, context, context.dataFlowInfo); }
@Override public JetTypeInfo visitProperty(JetProperty property, ExpressionTypingContext context) { JetTypeReference receiverTypeRef = property.getReceiverTypeRef(); if (receiverTypeRef != null) { context.trace.report(LOCAL_EXTENSION_PROPERTY.on(receiverTypeRef)); } JetPropertyAccessor getter = property.getGetter(); if (getter != null) { context.trace.report(LOCAL_VARIABLE_WITH_GETTER.on(getter)); } JetPropertyAccessor setter = property.getSetter(); if (setter != null) { context.trace.report(LOCAL_VARIABLE_WITH_SETTER.on(setter)); } VariableDescriptor propertyDescriptor = context .expressionTypingServices .getDescriptorResolver() .resolveLocalVariableDescriptor( scope.getContainingDeclaration(), scope, property, context.dataFlowInfo, context.trace); JetExpression initializer = property.getInitializer(); DataFlowInfo dataFlowInfo = context.dataFlowInfo; if (initializer != null) { JetType outType = propertyDescriptor.getType(); JetTypeInfo typeInfo = facade.getTypeInfo(initializer, context.replaceExpectedType(outType).replaceScope(scope)); dataFlowInfo = typeInfo.getDataFlowInfo(); } { VariableDescriptor olderVariable = scope.getLocalVariable(propertyDescriptor.getName()); ExpressionTypingUtils.checkVariableShadowing(context, propertyDescriptor, olderVariable); } scope.addVariableDescriptor(propertyDescriptor); ModifiersChecker.create(context.trace).checkModifiersForLocalDeclaration(property); return DataFlowUtils.checkStatementType(property, context, dataFlowInfo); }
@Override public JetTypeInfo visitMultiDeclaration( JetMultiDeclaration multiDeclaration, final ExpressionTypingContext context) { final JetExpression initializer = multiDeclaration.getInitializer(); if (initializer == null) { context.trace.report(INITIALIZER_REQUIRED_FOR_MULTIDECLARATION.on(multiDeclaration)); return JetTypeInfo.create(null, context.dataFlowInfo); } final ExpressionReceiver expressionReceiver = ExpressionTypingUtils.getExpressionReceiver( facade, initializer, context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE)); DataFlowInfo dataFlowInfo = facade.getTypeInfo(initializer, context).getDataFlowInfo(); if (expressionReceiver == null) { return JetTypeInfo.create(null, dataFlowInfo); } ExpressionTypingUtils.defineLocalVariablesFromMultiDeclaration( scope, multiDeclaration, expressionReceiver, initializer, context); return DataFlowUtils.checkStatementType(multiDeclaration, context, dataFlowInfo); }
@Override public JetType visitObjectLiteralExpression( final JetObjectLiteralExpression expression, final ExpressionTypingContext context) { final JetType[] result = new JetType[1]; ObservableBindingTrace.RecordHandler<PsiElement, ClassDescriptor> handler = new ObservableBindingTrace.RecordHandler<PsiElement, ClassDescriptor>() { @Override public void handleRecord( WritableSlice<PsiElement, ClassDescriptor> slice, PsiElement declaration, final ClassDescriptor descriptor) { if (slice == CLASS && declaration == expression.getObjectDeclaration()) { JetType defaultType = DeferredType.create( context.trace, new LazyValueWithDefault<JetType>( ErrorUtils.createErrorType("Recursive dependency")) { @Override protected JetType compute() { return descriptor.getDefaultType(); } }); result[0] = defaultType; if (!context.trace.get(PROCESSED, expression)) { context.trace.record(EXPRESSION_TYPE, expression, defaultType); context.trace.record(PROCESSED, expression); } } } }; ObservableBindingTrace traceAdapter = new ObservableBindingTrace(context.trace); traceAdapter.addHandler(CLASS, handler); TopDownAnalyzer.processObject( context.semanticServices, traceAdapter, context.scope, context.scope.getContainingDeclaration(), expression.getObjectDeclaration()); return DataFlowUtils.checkType(result[0], expression, context); }
@Override public JetTypeInfo visitObjectDeclaration( JetObjectDeclaration declaration, ExpressionTypingContext context) { TopDownAnalyzer.processClassOrObject( context.expressionTypingServices.getProject(), context.trace, scope, scope.getContainingDeclaration(), declaration); ClassDescriptor classDescriptor = context.trace.getBindingContext().get(BindingContext.CLASS, declaration); if (classDescriptor != null) { VariableDescriptor variableDescriptor = context .expressionTypingServices .getDescriptorResolver() .resolveObjectDeclaration( scope.getContainingDeclaration(), declaration, classDescriptor, context.trace); scope.addVariableDescriptor(variableDescriptor); } return DataFlowUtils.checkStatementType(declaration, context, context.dataFlowInfo); }
@Override public JetTypeInfo visitNamedFunction( JetNamedFunction function, ExpressionTypingContext context) { SimpleFunctionDescriptor functionDescriptor = context .expressionTypingServices .getDescriptorResolver() .resolveFunctionDescriptor( scope.getContainingDeclaration(), scope, function, context.trace); scope.addFunctionDescriptor(functionDescriptor); JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope( context.scope, functionDescriptor, context.trace); context.expressionTypingServices.checkFunctionReturnType( functionInnerScope, function, functionDescriptor, context.dataFlowInfo, null, context.trace); ModifiersChecker.create(context.trace).checkModifiersForLocalDeclaration(function); return DataFlowUtils.checkStatementType(function, context, context.dataFlowInfo); }
@Override public JetType visitFunctionLiteralExpression( JetFunctionLiteralExpression expression, ExpressionTypingContext context) { JetFunctionLiteral functionLiteral = expression.getFunctionLiteral(); JetBlockExpression bodyExpression = functionLiteral.getBodyExpression(); if (bodyExpression == null) return null; JetType expectedType = context.expectedType; boolean functionTypeExpected = expectedType != TypeUtils.NO_EXPECTED_TYPE && JetStandardClasses.isFunctionType(expectedType); NamedFunctionDescriptorImpl functionDescriptor = createFunctionDescriptor(expression, context, functionTypeExpected); List<JetType> parameterTypes = Lists.newArrayList(); List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters(); for (ValueParameterDescriptor valueParameter : valueParameters) { parameterTypes.add(valueParameter.getOutType()); } ReceiverDescriptor receiverParameter = functionDescriptor.getReceiverParameter(); JetType receiver = receiverParameter != NO_RECEIVER ? receiverParameter.getType() : null; JetType returnType = TypeUtils.NO_EXPECTED_TYPE; JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope( context.scope, functionDescriptor, context.trace); JetTypeReference returnTypeRef = functionLiteral.getReturnTypeRef(); if (returnTypeRef != null) { returnType = context.getTypeResolver().resolveType(context.scope, returnTypeRef); context .getServices() .checkFunctionReturnType( expression, context .replaceScope(functionInnerScope) .replaceExpectedType(returnType) .replaceExpectedReturnType(returnType) .replaceDataFlowInfo(context.dataFlowInfo)); } else { if (functionTypeExpected) { returnType = JetStandardClasses.getReturnTypeFromFunctionType(expectedType); } returnType = context .getServices() .getBlockReturnedType( functionInnerScope, bodyExpression, CoercionStrategy.COERCION_TO_UNIT, context.replaceExpectedType(returnType).replaceExpectedReturnType(returnType)); } JetType safeReturnType = returnType == null ? ErrorUtils.createErrorType("<return type>") : returnType; functionDescriptor.setReturnType(safeReturnType); boolean hasDeclaredValueParameters = functionLiteral.getValueParameterList() != null; if (!hasDeclaredValueParameters && functionTypeExpected) { JetType expectedReturnType = JetStandardClasses.getReturnTypeFromFunctionType(expectedType); if (JetStandardClasses.isUnit(expectedReturnType)) { functionDescriptor.setReturnType(JetStandardClasses.getUnitType()); return DataFlowUtils.checkType( JetStandardClasses.getFunctionType( Collections.<AnnotationDescriptor>emptyList(), receiver, parameterTypes, JetStandardClasses.getUnitType()), expression, context); } } return DataFlowUtils.checkType( JetStandardClasses.getFunctionType( Collections.<AnnotationDescriptor>emptyList(), receiver, parameterTypes, safeReturnType), expression, context); }
@Override public JetTypeInfo visitDeclaration(JetDeclaration dcl, ExpressionTypingContext context) { return DataFlowUtils.checkStatementType(dcl, context, context.dataFlowInfo); }