@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); }
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 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); }
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); }
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); }
@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); }