@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);
  }
  @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);
  }
Exemplo n.º 3
0
  @NotNull
  /*package*/ OverloadResolutionResultsImpl<FunctionDescriptor> resolveFunctionCall(
      @NotNull BasicCallResolutionContext context) {

    ProgressIndicatorProvider.checkCanceled();

    List<ResolutionTask<CallableDescriptor, FunctionDescriptor>> prioritizedTasks;

    JetExpression calleeExpression = context.call.getCalleeExpression();
    JetReferenceExpression functionReference;
    if (calleeExpression instanceof JetSimpleNameExpression) {
      JetSimpleNameExpression expression = (JetSimpleNameExpression) calleeExpression;
      functionReference = expression;

      ExpressionTypingUtils.checkCapturingInClosure(expression, context.trace, context.scope);

      Name name = expression.getReferencedNameAsName();

      prioritizedTasks =
          TaskPrioritizer.<CallableDescriptor, FunctionDescriptor>computePrioritizedTasks(
              context,
              name,
              functionReference,
              CallableDescriptorCollectors.FUNCTIONS_AND_VARIABLES);
      ResolutionTask.DescriptorCheckStrategy abstractConstructorCheck =
          new ResolutionTask.DescriptorCheckStrategy() {
            @Override
            public <D extends CallableDescriptor> boolean performAdvancedChecks(
                D descriptor, BindingTrace trace, TracingStrategy tracing) {
              if (descriptor instanceof ConstructorDescriptor) {
                Modality modality =
                    ((ConstructorDescriptor) descriptor).getContainingDeclaration().getModality();
                if (modality == Modality.ABSTRACT) {
                  tracing.instantiationOfAbstractClass(trace);
                  return false;
                }
              }
              return true;
            }
          };
      for (ResolutionTask task : prioritizedTasks) {
        task.setCheckingStrategy(abstractConstructorCheck);
      }
    } else {
      JetValueArgumentList valueArgumentList = context.call.getValueArgumentList();
      PsiElement reportAbsenceOn =
          valueArgumentList == null ? context.call.getCallElement() : valueArgumentList;
      if (calleeExpression instanceof JetConstructorCalleeExpression) {
        assert !context.call.getExplicitReceiver().exists();

        JetConstructorCalleeExpression expression =
            (JetConstructorCalleeExpression) calleeExpression;
        functionReference = expression.getConstructorReferenceExpression();
        if (functionReference == null) {
          return checkArgumentTypesAndFail(context); // No type there
        }
        JetTypeReference typeReference = expression.getTypeReference();
        assert typeReference != null;
        JetType constructedType =
            typeResolver.resolveType(context.scope, typeReference, context.trace, true);

        if (constructedType.isError()) {
          return checkArgumentTypesAndFail(context);
        }

        DeclarationDescriptor declarationDescriptor =
            constructedType.getConstructor().getDeclarationDescriptor();
        if (declarationDescriptor instanceof ClassDescriptor) {
          ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
          Collection<ConstructorDescriptor> constructors = classDescriptor.getConstructors();
          if (constructors.isEmpty()) {
            context.trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn));
            return checkArgumentTypesAndFail(context);
          }
          Collection<ResolutionCandidate<CallableDescriptor>> candidates =
              TaskPrioritizer.<CallableDescriptor>convertWithImpliedThis(
                  context.scope,
                  Collections.<ReceiverValue>singletonList(NO_RECEIVER),
                  constructors);
          prioritizedTasks =
              TaskPrioritizer
                  .<CallableDescriptor, FunctionDescriptor>computePrioritizedTasksFromCandidates(
                      context, functionReference, candidates, null);
        } else {
          context.trace.report(NOT_A_CLASS.on(calleeExpression));
          return checkArgumentTypesAndFail(context);
        }
      } else if (calleeExpression instanceof JetThisReferenceExpression) {
        functionReference = (JetThisReferenceExpression) calleeExpression;
        DeclarationDescriptor containingDeclaration = context.scope.getContainingDeclaration();
        if (containingDeclaration instanceof ConstructorDescriptor) {
          containingDeclaration = containingDeclaration.getContainingDeclaration();
        }
        assert containingDeclaration instanceof ClassDescriptor;
        ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;

        Collection<ConstructorDescriptor> constructors = classDescriptor.getConstructors();
        if (constructors.isEmpty()) {
          context.trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn));
          return checkArgumentTypesAndFail(context);
        }
        List<ResolutionCandidate<CallableDescriptor>> candidates =
            ResolutionCandidate.<CallableDescriptor>convertCollection(
                constructors, JetPsiUtil.isSafeCall(context.call));
        prioritizedTasks =
            Collections.singletonList(
                new ResolutionTask<CallableDescriptor, FunctionDescriptor>(
                    candidates, functionReference, context)); // !! DataFlowInfo.EMPTY
      } else if (calleeExpression != null) {
        // Here we handle the case where the callee expression must be something of type function,
        // e.g. (foo.bar())(1, 2)
        JetType calleeType =
            expressionTypingServices.safeGetType(
                context.scope,
                calleeExpression,
                NO_EXPECTED_TYPE,
                context.dataFlowInfo,
                context
                    .trace); // We are actually expecting a function, but there seems to be no easy
                             // way of expressing this

        if (!KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(calleeType)) {
          //                    checkTypesWithNoCallee(trace, scope, call);
          if (!calleeType.isError()) {
            context.trace.report(CALLEE_NOT_A_FUNCTION.on(calleeExpression, calleeType));
          }
          return checkArgumentTypesAndFail(context);
        }

        FunctionDescriptorImpl functionDescriptor =
            new ExpressionAsFunctionDescriptor(
                context.scope.getContainingDeclaration(),
                Name.special("<for expression " + calleeExpression.getText() + ">"),
                calleeExpression);
        FunctionDescriptorUtil.initializeFromFunctionType(
            functionDescriptor,
            calleeType,
            NO_RECEIVER_PARAMETER,
            Modality.FINAL,
            Visibilities.LOCAL);
        ResolutionCandidate<CallableDescriptor> resolutionCandidate =
            ResolutionCandidate.<CallableDescriptor>create(
                functionDescriptor, JetPsiUtil.isSafeCall(context.call));
        resolutionCandidate.setReceiverArgument(context.call.getExplicitReceiver());
        resolutionCandidate.setExplicitReceiverKind(ExplicitReceiverKind.RECEIVER_ARGUMENT);

        // strictly speaking, this is a hack:
        // we need to pass a reference, but there's no reference in the PSI,
        // so we wrap what we have into a fake reference and pass it on (unwrap on the other end)
        functionReference = new JetFakeReference(calleeExpression);

        prioritizedTasks =
            Collections.singletonList(
                new ResolutionTask<CallableDescriptor, FunctionDescriptor>(
                    Collections.singleton(resolutionCandidate), functionReference, context));
      } else {
        //                checkTypesWithNoCallee(trace, scope, call);
        return checkArgumentTypesAndFail(context);
      }
    }

    return doResolveCallOrGetCachedResults(
        ResolutionResultsCache.FUNCTION_MEMBER_TYPE,
        context,
        prioritizedTasks,
        CallTransformer.FUNCTION_CALL_TRANSFORMER,
        functionReference);
  }