@Nullable
  private static JetType computeUnsafeReturnType(
      @NotNull JetFunctionLiteralExpression expression,
      @NotNull ExpressionTypingContext context,
      @NotNull SimpleFunctionDescriptorImpl functionDescriptor,
      @Nullable JetType expectedReturnType) {
    JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
    JetBlockExpression bodyExpression = functionLiteral.getBodyExpression();
    assert bodyExpression != null;

    JetScope functionInnerScope =
        FunctionDescriptorUtil.getFunctionInnerScope(
            context.scope, functionDescriptor, context.trace);
    JetTypeReference returnTypeRef = functionLiteral.getReturnTypeRef();
    JetType declaredReturnType = null;
    if (returnTypeRef != null) {
      declaredReturnType =
          context
              .expressionTypingServices
              .getTypeResolver()
              .resolveType(context.scope, returnTypeRef, context.trace, true);
      // This is needed for ControlStructureTypingVisitor#visitReturnExpression() to properly
      // type-check returned expressions
      functionDescriptor.setReturnType(declaredReturnType);
      if (expectedReturnType != null) {
        if (!JetTypeChecker.INSTANCE.isSubtypeOf(declaredReturnType, expectedReturnType)) {
          context.trace.report(EXPECTED_RETURN_TYPE_MISMATCH.on(returnTypeRef, expectedReturnType));
        }
      }
    }

    // Type-check the body
    ExpressionTypingContext newContext =
        context
            .replaceScope(functionInnerScope)
            .replaceExpectedType(
                declaredReturnType != null
                    ? declaredReturnType
                    : (expectedReturnType != null ? expectedReturnType : NO_EXPECTED_TYPE));

    JetType typeOfBodyExpression =
        context
            .expressionTypingServices
            .getBlockReturnedType(bodyExpression, COERCION_TO_UNIT, newContext)
            .getType();

    List<JetType> returnedExpressionTypes =
        Lists.newArrayList(
            getTypesOfLocallyReturnedExpressions(
                functionLiteral, context.trace, collectReturns(bodyExpression)));
    ContainerUtil.addIfNotNull(returnedExpressionTypes, typeOfBodyExpression);

    if (declaredReturnType != null) return declaredReturnType;
    if (returnedExpressionTypes.isEmpty()) return null;
    return CommonSupertypes.commonSupertype(returnedExpressionTypes);
  }
Example #2
0
  private void resolveFunctionBody(
      @NotNull BindingTrace trace,
      @NotNull JetDeclarationWithBody function,
      @NotNull FunctionDescriptor functionDescriptor,
      @NotNull JetScope declaringScope) {
    if (!context.completeAnalysisNeeded(function)) return;

    JetExpression bodyExpression = function.getBodyExpression();
    JetScope functionInnerScope =
        FunctionDescriptorUtil.getFunctionInnerScope(declaringScope, functionDescriptor, trace);
    if (bodyExpression != null) {
      expressionTypingServices.checkFunctionReturnType(
          functionInnerScope, function, functionDescriptor, trace);
    }

    List<JetParameter> valueParameters = function.getValueParameters();
    List<ValueParameterDescriptor> valueParameterDescriptors =
        functionDescriptor.getValueParameters();

    checkDefaultParameterValues(valueParameters, valueParameterDescriptors, functionInnerScope);

    assert functionDescriptor.getReturnType() != null;
  }
  @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);
  }
Example #4
0
  private void resolveSecondaryConstructorBody(
      JetSecondaryConstructor declaration, final ConstructorDescriptor descriptor) {
    if (!context.completeAnalysisNeeded(declaration)) return;
    MutableClassDescriptor classDescriptor =
        (MutableClassDescriptor) descriptor.getContainingDeclaration();
    final JetScope scopeForSupertypeInitializers =
        FunctionDescriptorUtil.getFunctionInnerScope(
            classDescriptor.getScopeForSupertypeResolution(), descriptor, trace);
    // contains only constructor parameters
    final JetScope scopeForConstructorBody =
        FunctionDescriptorUtil.getFunctionInnerScope(
            classDescriptor.getScopeForInitializers(), descriptor, trace);
    // contains members & backing fields

    final DataFlowInfo dataFlowInfo = DataFlowInfo.EMPTY; // TODO: dataFlowInfo

    PsiElement nameElement = declaration.getNameNode().getPsi();
    if (classDescriptor.getUnsubstitutedPrimaryConstructor() == null) {
      trace.report(SECONDARY_CONSTRUCTOR_BUT_NO_PRIMARY.on(nameElement));
    } else {
      List<JetDelegationSpecifier> initializers = declaration.getInitializers();
      if (initializers.isEmpty()) {
        trace.report(SECONDARY_CONSTRUCTOR_NO_INITIALIZER_LIST.on(nameElement));
      } else {
        initializers
            .get(0)
            .accept(
                new JetVisitorVoid() {
                  @Override
                  public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) {
                    JetTypeReference typeReference = call.getTypeReference();
                    if (typeReference != null) {
                      callResolver.resolveFunctionCall(
                          trace,
                          scopeForSupertypeInitializers,
                          CallMaker.makeCall(ReceiverDescriptor.NO_RECEIVER, null, call),
                          NO_EXPECTED_TYPE,
                          dataFlowInfo);
                    }
                  }

                  @Override
                  public void visitDelegationToThisCall(JetDelegatorToThisCall call) {
                    // TODO : check that there's no recursion in this() calls
                    // TODO : check: if a this() call is present, no other initializers are allowed
                    ClassDescriptor classDescriptor = descriptor.getContainingDeclaration();

                    callResolver.resolveFunctionCall(
                        trace,
                        scopeForSupertypeInitializers,
                        CallMaker.makeCall(ReceiverDescriptor.NO_RECEIVER, null, call),
                        NO_EXPECTED_TYPE,
                        dataFlowInfo);
                    //                                call.getThisReference(),
                    //                                classDescriptor,
                    //                                classDescriptor.getDefaultType(),
                    //                                call);
                    //                        trace.getErrorHandler().genericError(call.getNode(),
                    // "this-calls are not supported");
                  }

                  @Override
                  public void visitDelegationByExpressionSpecifier(
                      JetDelegatorByExpressionSpecifier specifier) {
                    trace.report(BY_IN_SECONDARY_CONSTRUCTOR.on(specifier));
                  }

                  @Override
                  public void visitDelegationToSuperClassSpecifier(
                      JetDelegatorToSuperClass specifier) {
                    trace.report(INITIALIZER_WITH_NO_ARGUMENTS.on(specifier));
                  }

                  @Override
                  public void visitDelegationSpecifier(JetDelegationSpecifier specifier) {
                    throw new IllegalStateException();
                  }
                });
        for (int i = 1, initializersSize = initializers.size(); i < initializersSize; i++) {
          JetDelegationSpecifier initializer = initializers.get(i);
          trace.report(MANY_CALLS_TO_THIS.on(initializer));
        }
      }
    }
    JetExpression bodyExpression = declaration.getBodyExpression();
    if (bodyExpression != null) {

      expressionTypingServices.checkFunctionReturnType(
          scopeForConstructorBody,
          declaration,
          descriptor,
          JetStandardClasses.getUnitType(),
          trace);
    }

    checkDefaultParameterValues(
        declaration.getValueParameters(), descriptor.getValueParameters(), scopeForConstructorBody);
  }
Example #5
0
  private void resolveDelegationSpecifierList(
      final JetClassOrObject jetClass, final MutableClassDescriptor descriptor) {
    if (!context.completeAnalysisNeeded(jetClass)) return;
    final ConstructorDescriptor primaryConstructor =
        descriptor.getUnsubstitutedPrimaryConstructor();
    final JetScope scopeForConstructor =
        primaryConstructor == null
            ? null
            : FunctionDescriptorUtil.getFunctionInnerScope(
                descriptor.getScopeForSupertypeResolution(), primaryConstructor, trace);
    final ExpressionTypingServices typeInferrer = expressionTypingServices; // TODO : flow

    final Map<JetTypeReference, JetType> supertypes = Maps.newLinkedHashMap();
    JetVisitorVoid visitor =
        new JetVisitorVoid() {
          private void recordSupertype(JetTypeReference typeReference, JetType supertype) {
            if (supertype == null) return;
            supertypes.put(typeReference, supertype);
          }

          @Override
          public void visitDelegationByExpressionSpecifier(
              JetDelegatorByExpressionSpecifier specifier) {
            if (descriptor.getKind() == ClassKind.TRAIT) {
              trace.report(DELEGATION_IN_TRAIT.on(specifier));
            }
            JetType supertype =
                trace.getBindingContext().get(BindingContext.TYPE, specifier.getTypeReference());
            recordSupertype(specifier.getTypeReference(), supertype);
            if (supertype != null) {
              DeclarationDescriptor declarationDescriptor =
                  supertype.getConstructor().getDeclarationDescriptor();
              if (declarationDescriptor instanceof ClassDescriptor) {
                ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
                if (classDescriptor.getKind() != ClassKind.TRAIT) {
                  trace.report(DELEGATION_NOT_TO_TRAIT.on(specifier.getTypeReference()));
                }
              }
            }
            JetExpression delegateExpression = specifier.getDelegateExpression();
            if (delegateExpression != null) {
              JetScope scope =
                  scopeForConstructor == null
                      ? descriptor.getScopeForMemberResolution()
                      : scopeForConstructor;
              JetType type =
                  typeInferrer.getType(scope, delegateExpression, NO_EXPECTED_TYPE, trace);
              if (type != null
                  && supertype != null
                  && !JetTypeChecker.INSTANCE.isSubtypeOf(type, supertype)) {
                trace.report(TYPE_MISMATCH.on(delegateExpression, supertype, type));
              }
            }
          }

          @Override
          public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) {
            JetValueArgumentList valueArgumentList = call.getValueArgumentList();
            PsiElement elementToMark = valueArgumentList == null ? call : valueArgumentList;
            if (descriptor.getKind() == ClassKind.TRAIT) {
              trace.report(SUPERTYPE_INITIALIZED_IN_TRAIT.on(elementToMark));
            }
            JetTypeReference typeReference = call.getTypeReference();
            if (typeReference == null) return;
            if (descriptor.getUnsubstitutedPrimaryConstructor() == null) {
              assert descriptor.getKind() == ClassKind.TRAIT;
              return;
            }
            OverloadResolutionResults<FunctionDescriptor> results =
                callResolver.resolveFunctionCall(
                    trace,
                    scopeForConstructor,
                    CallMaker.makeCall(ReceiverDescriptor.NO_RECEIVER, null, call),
                    NO_EXPECTED_TYPE,
                    DataFlowInfo.EMPTY);
            if (results.isSuccess()) {
              JetType supertype = results.getResultingDescriptor().getReturnType();
              recordSupertype(typeReference, supertype);
              ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype);
              if (classDescriptor != null) {
                if (classDescriptor.getKind() == ClassKind.TRAIT) {
                  trace.report(CONSTRUCTOR_IN_TRAIT.on(elementToMark));
                }
              }
            } else {
              recordSupertype(
                  typeReference, trace.getBindingContext().get(BindingContext.TYPE, typeReference));
            }
          }

          @Override
          public void visitDelegationToSuperClassSpecifier(JetDelegatorToSuperClass specifier) {
            JetTypeReference typeReference = specifier.getTypeReference();
            JetType supertype = trace.getBindingContext().get(BindingContext.TYPE, typeReference);
            recordSupertype(typeReference, supertype);
            if (supertype == null) return;
            ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype);
            if (classDescriptor == null) return;
            if (descriptor.getKind() != ClassKind.TRAIT
                && classDescriptor.hasConstructors()
                && !ErrorUtils.isError(classDescriptor.getTypeConstructor())
                && classDescriptor.getKind() != ClassKind.TRAIT) {
              boolean hasConstructorWithoutParams = false;
              for (ConstructorDescriptor constructor : classDescriptor.getConstructors()) {
                if (constructor.getValueParameters().isEmpty()) {
                  hasConstructorWithoutParams = true;
                }
              }
              if (!hasConstructorWithoutParams) {
                trace.report(SUPERTYPE_NOT_INITIALIZED.on(specifier));
              } else {
                trace.report(SUPERTYPE_NOT_INITIALIZED_DEFAULT.on(specifier));
              }
            }
          }

          @Override
          public void visitDelegationToThisCall(JetDelegatorToThisCall thisCall) {
            throw new IllegalStateException("This-calls should be prohibited by the parser");
          }

          @Override
          public void visitJetElement(JetElement element) {
            throw new UnsupportedOperationException(element.getText() + " : " + element);
          }
        };

    for (JetDelegationSpecifier delegationSpecifier : jetClass.getDelegationSpecifiers()) {
      delegationSpecifier.accept(visitor);
    }

    Set<TypeConstructor> parentEnum = Collections.emptySet();
    if (jetClass instanceof JetEnumEntry) {
      parentEnum =
          Collections.singleton(
              ((ClassDescriptor) descriptor.getContainingDeclaration().getContainingDeclaration())
                  .getTypeConstructor());
    }

    checkSupertypeList(descriptor, supertypes, parentEnum);
  }