@NotNull public OverloadResolutionResults<VariableDescriptor> resolveSimpleProperty( @NotNull BasicCallResolutionContext context) { JetExpression calleeExpression = context.call.getCalleeExpression(); assert calleeExpression instanceof JetSimpleNameExpression; JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) calleeExpression; Name referencedName = nameExpression.getReferencedNameAsName(); List<CallableDescriptorCollector<? extends VariableDescriptor>> callableDescriptorCollectors = Lists.newArrayList(); if (nameExpression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) { referencedName = Name.identifier(referencedName.asString().substring(1)); callableDescriptorCollectors.add(CallableDescriptorCollectors.PROPERTIES); } else { callableDescriptorCollectors.add(CallableDescriptorCollectors.VARIABLES); } List<ResolutionTask<VariableDescriptor, VariableDescriptor>> prioritizedTasks = TaskPrioritizer.<VariableDescriptor, VariableDescriptor>computePrioritizedTasks( context, referencedName, nameExpression, callableDescriptorCollectors); return doResolveCallOrGetCachedResults( ResolutionResultsCache.PROPERTY_MEMBER_TYPE, context, prioritizedTasks, CallTransformer.PROPERTY_CALL_TRANSFORMER, nameExpression); }
@Nullable private static Name getCallerName(@NotNull JetFunctionLiteralExpression expression) { JetCallExpression callExpression = getContainingCallExpression(expression); if (callExpression == null) return null; JetExpression calleeExpression = callExpression.getCalleeExpression(); if (calleeExpression instanceof JetSimpleNameExpression) { JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) calleeExpression; return nameExpression.getReferencedNameAsName(); } return null; }
@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()); }
@Nullable private NamespaceType lookupNamespaceType( @NotNull JetSimpleNameExpression expression, @NotNull ResolutionContext context) { Name name = expression.getReferencedNameAsName(); NamespaceDescriptor namespace = context.scope.getNamespace(name); if (namespace == null) { return null; } context.trace.record(REFERENCE_TARGET, expression, namespace); // Construct a NamespaceType with everything from the namespace and with nested classes of the // corresponding class (if any) JetScope scope; ClassifierDescriptor classifier = context.scope.getClassifier(name); if (classifier instanceof ClassDescriptor) { scope = new ChainedScope( namespace, namespace.getMemberScope(), getStaticNestedClassesScope((ClassDescriptor) classifier)); } else { scope = namespace.getMemberScope(); } return new NamespaceType(name, scope); }
@Nullable private JetType lookupNamespaceOrClassObject( @NotNull JetSimpleNameExpression expression, @NotNull ResolutionContext context) { Name referencedName = expression.getReferencedNameAsName(); final ClassifierDescriptor classifier = context.scope.getClassifier(referencedName); if (classifier != null) { JetType classObjectType = classifier.getClassObjectType(); if (classObjectType != null) { context.trace.record(REFERENCE_TARGET, expression, classifier); JetType result = getExtendedClassObjectType(classObjectType, referencedName, classifier, context); if (result == null) { context.trace.report(NO_CLASS_OBJECT.on(expression, classifier)); } return DataFlowUtils.checkType(result, expression, context); } } JetType[] result = new JetType[1]; TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create( context.trace, "trace for namespace/class object lookup of name", referencedName); if (furtherNameLookup(expression, result, context.replaceBindingTrace(temporaryTrace))) { temporaryTrace.commit(); return DataFlowUtils.checkType(result[0], expression, context); } // To report NO_CLASS_OBJECT when no namespace found if (classifier != null) { if (classifier instanceof TypeParameterDescriptor) { if (context.expressionPosition == ExpressionPosition.FREE) { context.trace.report( TYPE_PARAMETER_IS_NOT_AN_EXPRESSION.on( expression, (TypeParameterDescriptor) classifier)); } else { context.trace.report( TYPE_PARAMETER_ON_LHS_OF_DOT.on(expression, (TypeParameterDescriptor) classifier)); } } else if (context.expressionPosition == ExpressionPosition.FREE) { context.trace.report(NO_CLASS_OBJECT.on(expression, classifier)); } context.trace.record(REFERENCE_TARGET, expression, classifier); JetScope scopeForStaticMembersResolution = classifier instanceof ClassDescriptor ? getStaticNestedClassesScope((ClassDescriptor) classifier) : new JetScopeImpl() { @NotNull @Override public DeclarationDescriptor getContainingDeclaration() { return classifier; } @Override public String toString() { return "Scope for the type parameter on the left hand side of dot"; } }; return new NamespaceType(referencedName, scopeForStaticMembersResolution); } temporaryTrace.commit(); return result[0]; }
@Nullable private JetType lookupNamespaceOrClassObject( @NotNull JetSimpleNameExpression expression, @NotNull ResolutionContext context) { Name referencedName = expression.getReferencedNameAsName(); ClassifierDescriptor classifier = context.scope.getClassifier(referencedName); if (classifier != null) { JetType classObjectType = classifier.getClassObjectType(); if (classObjectType != null) { context.trace.record(REFERENCE_TARGET, expression, classifier); JetType result; if (context.expressionPosition == ExpressionPosition.LHS_OF_DOT && classifier instanceof ClassDescriptor) { JetScope scope = new ChainedScope( classifier, classObjectType.getMemberScope(), getStaticNestedClassesScope((ClassDescriptor) classifier)); result = new NamespaceType(referencedName, scope); } else if (context.expressionPosition == ExpressionPosition.LHS_OF_DOT || classifier.isClassObjectAValue()) { result = classObjectType; } else { context.trace.report(NO_CLASS_OBJECT.on(expression, classifier)); result = null; } return DataFlowUtils.checkType(result, expression, context); } } JetType[] result = new JetType[1]; TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create( context.trace, "trace for namespace/class object lookup of name", referencedName); if (furtherNameLookup(expression, result, context.replaceBindingTrace(temporaryTrace))) { temporaryTrace.commit(); return DataFlowUtils.checkType(result[0], expression, context); } // To report NO_CLASS_OBJECT when no namespace found if (classifier != null) { if (context.expressionPosition == ExpressionPosition.FREE) { context.trace.report(NO_CLASS_OBJECT.on(expression, classifier)); } context.trace.record(REFERENCE_TARGET, expression, classifier); JetScope scopeForStaticMembersResolution = classifier instanceof ClassDescriptor ? getStaticNestedClassesScope((ClassDescriptor) classifier) : JetScope.EMPTY; return new NamespaceType(referencedName, scopeForStaticMembersResolution); } temporaryTrace.commit(); return result[0]; }
private boolean furtherNameLookup( @NotNull JetSimpleNameExpression expression, @NotNull JetType[] result, @NotNull ResolutionContext context) { NamespaceType namespaceType = lookupNamespaceType(expression, context); if (namespaceType == null) { return false; } if (context.expressionPosition == ExpressionPosition.LHS_OF_DOT) { result[0] = namespaceType; return true; } context.trace.report(EXPRESSION_EXPECTED_NAMESPACE_FOUND.on(expression)); result[0] = ErrorUtils.createErrorType("Type for " + expression.getReferencedNameAsName()); return false; }
@NotNull private LookupResult lookupSimpleNameReference( @NotNull JetSimpleNameExpression referenceExpression, @NotNull JetScope outerScope, @NotNull LookupMode lookupMode, boolean namespaceLevel) { Name referencedName = referenceExpression.getReferencedNameAsName(); Set<DeclarationDescriptor> descriptors = Sets.newHashSet(); NamespaceDescriptor namespaceDescriptor = outerScope.getNamespace(referencedName); if (namespaceDescriptor != null) { descriptors.add(namespaceDescriptor); } ClassifierDescriptor classifierDescriptor = outerScope.getClassifier(referencedName); if (classifierDescriptor != null) { descriptors.add(classifierDescriptor); } if (lookupMode == LookupMode.ONLY_CLASSES) { ClassDescriptor objectDescriptor = outerScope.getObjectDescriptor(referencedName); if (objectDescriptor != null) { descriptors.add(objectDescriptor); } } else { descriptors.addAll(outerScope.getFunctions(referencedName)); descriptors.addAll(outerScope.getProperties(referencedName)); VariableDescriptor localVariable = outerScope.getLocalVariable(referencedName); if (localVariable != null) { descriptors.add(localVariable); } } return new SuccessfulLookupResult(descriptors, outerScope, namespaceLevel); }
@NotNull protected JetTypeInfo visitAssignmentOperation( JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) { // There is a temporary binding trace for an opportunity to resolve set method for array if // needed (the initial trace should be used there) TemporaryBindingTrace temporaryBindingTrace = TemporaryBindingTrace.create( contextWithExpectedType.trace, "trace to resolve array set method for binary expression", expression); ExpressionTypingContext context = contextWithExpectedType .replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE) .replaceBindingTrace(temporaryBindingTrace); JetSimpleNameExpression operationSign = expression.getOperationReference(); IElementType operationType = operationSign.getReferencedNameElementType(); JetTypeInfo leftInfo = facade.getTypeInfo(expression.getLeft(), context); JetType leftType = leftInfo.getType(); DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo(); JetExpression right = expression.getRight(); JetExpression left = JetPsiUtil.deparenthesizeWithNoTypeResolution(expression.getLeft()); if (right == null || left == null) { temporaryBindingTrace.commit(); return JetTypeInfo.create(null, dataFlowInfo); } if (leftType == null) { dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo(); context.trace.report(UNRESOLVED_REFERENCE.on(operationSign)); temporaryBindingTrace.commit(); return JetTypeInfo.create(null, dataFlowInfo); } ExpressionReceiver receiver = new ExpressionReceiver(left, leftType); // We check that defined only one of '+=' and '+' operations, and call it (in the case '+' we // then also assign) // Check for '+=' Name name = OperatorConventions.ASSIGNMENT_OPERATIONS.get(operationType); TemporaryBindingTrace assignmentOperationTrace = TemporaryBindingTrace.create( context.trace, "trace to check assignment operation like '+=' for", expression); OverloadResolutionResults<FunctionDescriptor> assignmentOperationDescriptors = basic.getResolutionResultsForBinaryCall( scope, name, context.replaceBindingTrace(assignmentOperationTrace), expression, receiver); JetType assignmentOperationType = OverloadResolutionResultsUtil.getResultType(assignmentOperationDescriptors); // Check for '+' Name counterpartName = OperatorConventions.BINARY_OPERATION_NAMES.get( OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(operationType)); TemporaryBindingTrace binaryOperationTrace = TemporaryBindingTrace.create( context.trace, "trace to check binary operation like '+' for", expression); OverloadResolutionResults<FunctionDescriptor> binaryOperationDescriptors = basic.getResolutionResultsForBinaryCall( scope, counterpartName, context.replaceBindingTrace(binaryOperationTrace), expression, receiver); JetType binaryOperationType = OverloadResolutionResultsUtil.getResultType(binaryOperationDescriptors); JetType type = assignmentOperationType != null ? assignmentOperationType : binaryOperationType; if (assignmentOperationType != null && binaryOperationType != null) { OverloadResolutionResults<FunctionDescriptor> ambiguityResolutionResults = OverloadResolutionResultsUtil.ambiguity( assignmentOperationDescriptors, binaryOperationDescriptors); context.trace.report( ASSIGN_OPERATOR_AMBIGUITY.on( operationSign, ambiguityResolutionResults.getResultingCalls())); Collection<DeclarationDescriptor> descriptors = Sets.newHashSet(); for (ResolvedCall<? extends FunctionDescriptor> call : ambiguityResolutionResults.getResultingCalls()) { descriptors.add(call.getResultingDescriptor()); } dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo(); context.trace.record(AMBIGUOUS_REFERENCE_TARGET, operationSign, descriptors); } else if (assignmentOperationType != null) { assignmentOperationTrace.commit(); if (!KotlinBuiltIns.getInstance().isUnit(assignmentOperationType)) { context.trace.report( ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT.on( operationSign, assignmentOperationDescriptors.getResultingDescriptor(), operationSign)); } } else { binaryOperationTrace.commit(); context.trace.record(VARIABLE_REASSIGNMENT, expression); if (left instanceof JetArrayAccessExpression) { ExpressionTypingContext contextForResolve = context .replaceScope(scope) .replaceBindingTrace( TemporaryBindingTrace.create( contextWithExpectedType.trace, "trace to resolve array set method for assignment", expression)); basic.resolveArrayAccessSetMethod( (JetArrayAccessExpression) left, right, contextForResolve, context.trace); } dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo(); } basic.checkLValue(context.trace, expression.getLeft()); temporaryBindingTrace.commit(); return JetTypeInfo.create( checkAssignmentType(type, expression, contextWithExpectedType), dataFlowInfo); }
@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); }