001/* 002 * Copyright 2010-2013 JetBrains s.r.o. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.jetbrains.jet.lang.resolve.calls; 018 019import com.google.common.base.Function; 020import com.google.common.collect.Collections2; 021import com.google.common.collect.Lists; 022import com.intellij.psi.PsiElement; 023import org.jetbrains.annotations.NotNull; 024import org.jetbrains.jet.lang.descriptors.CallableDescriptor; 025import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; 026import org.jetbrains.jet.lang.descriptors.VariableDescriptor; 027import org.jetbrains.jet.lang.psi.*; 028import org.jetbrains.jet.lang.resolve.ChainedTemporaryBindingTrace; 029import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace; 030import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace; 031import org.jetbrains.jet.lang.resolve.calls.context.BasicCallResolutionContext; 032import org.jetbrains.jet.lang.resolve.calls.context.CallCandidateResolutionContext; 033import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallImpl; 034import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace; 035import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall; 036import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults; 037import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl; 038import org.jetbrains.jet.lang.resolve.calls.tasks.ExplicitReceiverKind; 039import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionCandidate; 040import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionTask; 041import org.jetbrains.jet.lang.resolve.calls.util.DelegatingCall; 042import org.jetbrains.jet.lang.resolve.name.Name; 043import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; 044import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; 045import org.jetbrains.jet.lang.types.JetType; 046 047import java.util.Collection; 048import java.util.Collections; 049import java.util.List; 050 051/** 052 * CallTransformer treats specially 'variable as function' call case, other cases keeps unchanged (base realization). 053 * 054 * For the call 'b.foo(1)' where foo is a variable that has method 'invoke' (for example of function type) 055 * CallTransformer creates two contexts, two calls in each, and performs second ('invoke') call resolution: 056 * 057 * context#1. calls: 'b.foo' 'invoke(1)' 058 * context#2. calls: 'foo' 'b.invoke(1)' 059 * 060 * If success VariableAsFunctionResolvedCall is created. 061 */ 062public class CallTransformer<D extends CallableDescriptor, F extends D> { 063 private CallTransformer() {} 064 065 /** 066 * Returns two contexts for 'variable as function' case (in FUNCTION_CALL_TRANSFORMER), one context otherwise 067 */ 068 @NotNull 069 public Collection<CallCandidateResolutionContext<D>> createCallContexts(@NotNull ResolutionCandidate<D> candidate, 070 @NotNull ResolutionTask<D, F> task, 071 @NotNull TemporaryBindingTrace candidateTrace) { 072 073 ResolvedCallImpl<D> candidateCall = ResolvedCallImpl.create(candidate, candidateTrace, task.tracing); 074 return Collections.singleton(CallCandidateResolutionContext.create(candidateCall, task, candidateTrace, task.tracing)); 075 } 076 077 /** 078 * Returns collection of resolved calls for 'invoke' for 'variable as function' case (in FUNCTION_CALL_TRANSFORMER), 079 * the resolved call from callCandidateResolutionContext otherwise 080 */ 081 @NotNull 082 public Collection<ResolvedCallWithTrace<F>> transformCall(@NotNull CallCandidateResolutionContext<D> callCandidateResolutionContext, 083 @NotNull CallResolver callResolver, 084 @NotNull ResolutionTask<D, F> task) { 085 086 return Collections.singleton((ResolvedCallWithTrace<F>) callCandidateResolutionContext.candidateCall); 087 } 088 089 090 public static CallTransformer<VariableDescriptor, VariableDescriptor> PROPERTY_CALL_TRANSFORMER = new CallTransformer<VariableDescriptor, VariableDescriptor>(); 091 092 public static CallTransformer<CallableDescriptor, FunctionDescriptor> FUNCTION_CALL_TRANSFORMER = new CallTransformer<CallableDescriptor, FunctionDescriptor>() { 093 @NotNull 094 @Override 095 public Collection<CallCandidateResolutionContext<CallableDescriptor>> createCallContexts(@NotNull ResolutionCandidate<CallableDescriptor> candidate, 096 @NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task, @NotNull TemporaryBindingTrace candidateTrace) { 097 098 if (candidate.getDescriptor() instanceof FunctionDescriptor) { 099 return super.createCallContexts(candidate, task, candidateTrace); 100 } 101 102 assert candidate.getDescriptor() instanceof VariableDescriptor; 103 104 boolean hasReceiver = candidate.getReceiverArgument().exists(); 105 Call variableCall = stripCallArguments(task); 106 if (!hasReceiver) { 107 CallCandidateResolutionContext<CallableDescriptor> context = CallCandidateResolutionContext.create( 108 ResolvedCallImpl.create(candidate, candidateTrace, task.tracing), task, candidateTrace, task.tracing, variableCall); 109 return Collections.singleton(context); 110 } 111 Call variableCallWithoutReceiver = stripReceiver(variableCall); 112 CallCandidateResolutionContext<CallableDescriptor> contextWithReceiver = createContextWithChainedTrace( 113 candidate, variableCall, candidateTrace, task); 114 115 ResolutionCandidate<CallableDescriptor> candidateWithoutReceiver = ResolutionCandidate.create( 116 candidate.getDescriptor(), candidate.getThisObject(), ReceiverValue.NO_RECEIVER, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, false); 117 118 CallCandidateResolutionContext<CallableDescriptor> contextWithoutReceiver = createContextWithChainedTrace( 119 candidateWithoutReceiver, variableCallWithoutReceiver, candidateTrace, task); 120 121 contextWithoutReceiver.receiverForVariableAsFunctionSecondCall = variableCall.getExplicitReceiver(); 122 123 return Lists.newArrayList(contextWithReceiver, contextWithoutReceiver); 124 } 125 126 private CallCandidateResolutionContext<CallableDescriptor> createContextWithChainedTrace(ResolutionCandidate<CallableDescriptor> candidate, 127 Call call, TemporaryBindingTrace temporaryTrace, ResolutionTask<CallableDescriptor, FunctionDescriptor> task) { 128 129 ChainedTemporaryBindingTrace chainedTrace = ChainedTemporaryBindingTrace.create(temporaryTrace, "chained trace to resolve candidate", candidate); 130 ResolvedCallImpl<CallableDescriptor> resolvedCall = ResolvedCallImpl.create(candidate, chainedTrace, task.tracing); 131 return CallCandidateResolutionContext.create(resolvedCall, task, chainedTrace, task.tracing, call); 132 } 133 134 private Call stripCallArguments(@NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task) { 135 return new DelegatingCall(task.call) { 136 @Override 137 public JetValueArgumentList getValueArgumentList() { 138 return null; 139 } 140 141 @NotNull 142 @Override 143 public List<? extends ValueArgument> getValueArguments() { 144 return Collections.emptyList(); 145 } 146 147 @NotNull 148 @Override 149 public List<JetExpression> getFunctionLiteralArguments() { 150 return Collections.emptyList(); 151 } 152 153 @NotNull 154 @Override 155 public List<JetTypeProjection> getTypeArguments() { 156 return Collections.emptyList(); 157 } 158 159 @Override 160 public JetTypeArgumentList getTypeArgumentList() { 161 return null; 162 } 163 }; 164 } 165 166 private Call stripReceiver(@NotNull Call variableCall) { 167 return new DelegatingCall(variableCall) { 168 @NotNull 169 @Override 170 public ReceiverValue getExplicitReceiver() { 171 return ReceiverValue.NO_RECEIVER; 172 } 173 }; 174 } 175 176 @NotNull 177 @Override 178 public Collection<ResolvedCallWithTrace<FunctionDescriptor>> transformCall(@NotNull CallCandidateResolutionContext<CallableDescriptor> context, 179 @NotNull CallResolver callResolver, @NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task) { 180 181 CallableDescriptor descriptor = context.candidateCall.getCandidateDescriptor(); 182 if (descriptor instanceof FunctionDescriptor) { 183 return super.transformCall(context, callResolver, task); 184 } 185 186 assert descriptor instanceof VariableDescriptor; 187 JetType returnType = descriptor.getReturnType(); 188 if (returnType == null) { 189 return Collections.emptyList(); 190 } 191 192 final ResolvedCallWithTrace<VariableDescriptor> variableResolvedCall = (ResolvedCallWithTrace)context.candidateCall; 193 194 Call functionCall = new CallForImplicitInvoke(context, task, returnType); 195 196 DelegatingBindingTrace variableCallTrace = context.candidateCall.getTrace(); 197 BasicCallResolutionContext basicCallResolutionContext = BasicCallResolutionContext.create( 198 variableCallTrace, context.scope, functionCall, context.expectedType, context.dataFlowInfo, 199 context.resolveMode, context.checkArguments, context.expressionPosition, context.resolutionResultsCache); 200 201 // 'invoke' call resolve 202 OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveCallWithGivenName(basicCallResolutionContext, task.reference, Name.identifier("invoke")); 203 Collection<ResolvedCallWithTrace<FunctionDescriptor>> calls = ((OverloadResolutionResultsImpl<FunctionDescriptor>)results).getResultingCalls(); 204 205 return Collections2.transform(calls, new Function<ResolvedCallWithTrace<FunctionDescriptor>, ResolvedCallWithTrace<FunctionDescriptor>>() { 206 @Override 207 public ResolvedCallWithTrace<FunctionDescriptor> apply(ResolvedCallWithTrace<FunctionDescriptor> functionResolvedCall) { 208 return new VariableAsFunctionResolvedCall(functionResolvedCall, variableResolvedCall); 209 } 210 }); 211 } 212 }; 213 214 public static class CallForImplicitInvoke extends DelegatingCall { 215 final Call outerCall; 216 final CallCandidateResolutionContext<CallableDescriptor> context; 217 final ExpressionReceiver receiverFromVariable; 218 final JetSimpleNameExpression invokeExpression; 219 220 private CallForImplicitInvoke(CallCandidateResolutionContext<CallableDescriptor> context, 221 ResolutionTask<CallableDescriptor, FunctionDescriptor> task, JetType returnType) { 222 super(task.call); 223 this.outerCall = task.call; 224 this.context = context; 225 this.receiverFromVariable = new ExpressionReceiver(task.reference, returnType); 226 this.invokeExpression = (JetSimpleNameExpression) JetPsiFactory.createExpression(task.call.getCallElement().getProject(), "invoke"); 227 } 228 @NotNull 229 @Override 230 public ReceiverValue getExplicitReceiver() { 231 return context.receiverForVariableAsFunctionSecondCall; 232 } 233 234 @NotNull 235 @Override 236 public ReceiverValue getThisObject() { 237 return receiverFromVariable; 238 } 239 240 @Override 241 public JetExpression getCalleeExpression() { 242 return invokeExpression; 243 } 244 245 @NotNull 246 @Override 247 public PsiElement getCallElement() { 248 if (outerCall.getCallElement() instanceof JetCallElement) { 249 //to report errors properly 250 JetValueArgumentList list = ((JetCallElement)outerCall.getCallElement()).getValueArgumentList(); 251 if (list != null) { 252 return list; 253 } 254 } 255 return invokeExpression; 256 } 257 258 @NotNull 259 @Override 260 public CallType getCallType() { 261 return CallType.INVOKE; 262 } 263 264 @NotNull 265 public Call getOuterCall() { 266 return outerCall; 267 } 268 } 269}