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.tasks; 018 019import com.google.common.collect.Lists; 020import com.intellij.openapi.progress.ProgressIndicatorProvider; 021import org.jetbrains.annotations.NotNull; 022import org.jetbrains.annotations.Nullable; 023import org.jetbrains.jet.lang.descriptors.*; 024import org.jetbrains.jet.lang.psi.JetExpression; 025import org.jetbrains.jet.lang.psi.JetReferenceExpression; 026import org.jetbrains.jet.lang.psi.JetSuperExpression; 027import org.jetbrains.jet.lang.resolve.DescriptorUtils; 028import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastServiceImpl; 029import org.jetbrains.jet.lang.resolve.calls.context.BasicCallResolutionContext; 030import org.jetbrains.jet.lang.resolve.name.Name; 031import org.jetbrains.jet.lang.resolve.scopes.JetScope; 032import org.jetbrains.jet.lang.resolve.scopes.JetScopeUtils; 033import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; 034import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; 035import org.jetbrains.jet.lang.types.ErrorUtils; 036import org.jetbrains.jet.lang.types.NamespaceType; 037import org.jetbrains.jet.lang.types.checker.JetTypeChecker; 038 039import java.util.Collection; 040import java.util.Collections; 041import java.util.List; 042 043import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isClassObject; 044import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.*; 045import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER; 046 047public class TaskPrioritizer { 048 049 public static <D extends CallableDescriptor> void splitLexicallyLocalDescriptors( 050 @NotNull Collection<ResolutionCandidate<D>> allDescriptors, 051 @NotNull DeclarationDescriptor containerOfTheCurrentLocality, 052 @NotNull Collection<ResolutionCandidate<D>> local, 053 @NotNull Collection<ResolutionCandidate<D>> nonlocal 054 ) { 055 for (ResolutionCandidate<D> resolvedCall : allDescriptors) { 056 if (DescriptorUtils.isLocal(containerOfTheCurrentLocality, resolvedCall.getDescriptor())) { 057 local.add(resolvedCall); 058 } 059 else { 060 nonlocal.add(resolvedCall); 061 } 062 } 063 } 064 065 @Nullable 066 public static JetSuperExpression getReceiverSuper(@NotNull ReceiverValue receiver) { 067 if (receiver instanceof ExpressionReceiver) { 068 ExpressionReceiver expressionReceiver = (ExpressionReceiver) receiver; 069 JetExpression expression = expressionReceiver.getExpression(); 070 if (expression instanceof JetSuperExpression) { 071 return (JetSuperExpression) expression; 072 } 073 } 074 return null; 075 } 076 077 @NotNull 078 public static <D extends CallableDescriptor, F extends D> List<ResolutionTask<D, F>> computePrioritizedTasks( 079 @NotNull BasicCallResolutionContext context, 080 @NotNull Name name, 081 @NotNull JetReferenceExpression functionReference, 082 @NotNull List<CallableDescriptorCollector<? extends D>> callableDescriptorCollectors 083 ) { 084 ReceiverValue explicitReceiver = context.call.getExplicitReceiver(); 085 JetScope scope; 086 if (explicitReceiver.exists() && explicitReceiver.getType() instanceof NamespaceType) { 087 // Receiver is a namespace 088 scope = explicitReceiver.getType().getMemberScope(); 089 explicitReceiver = NO_RECEIVER; 090 } 091 else { 092 scope = context.scope; 093 } 094 095 ResolutionTaskHolder<D, F> result = new ResolutionTaskHolder<D, F>(functionReference, context, new MyPriorityProvider<D>(context)); 096 TaskPrioritizerContext<D, F> c = new TaskPrioritizerContext<D, F>(name, result, context, scope, callableDescriptorCollectors); 097 doComputeTasks(explicitReceiver, c); 098 return result.getTasks(); 099 } 100 101 private static <D extends CallableDescriptor, F extends D> void doComputeTasks( 102 @NotNull ReceiverValue receiver, 103 @NotNull TaskPrioritizerContext<D, F> c 104 ) { 105 ProgressIndicatorProvider.checkCanceled(); 106 107 boolean resolveInvoke = c.context.call.getThisObject().exists(); 108 if (resolveInvoke) { 109 addCandidatesForInvoke(receiver, c); 110 return; 111 } 112 List<ReceiverValue> implicitReceivers = JetScopeUtils.getImplicitReceiversHierarchyValues(c.scope); 113 if (receiver.exists()) { 114 addCandidatesForExplicitReceiver(receiver, implicitReceivers, c, /*resolveInvoke=*/false); 115 return; 116 } 117 addCandidatesForNoReceiver(implicitReceivers, c); 118 } 119 120 private static <D extends CallableDescriptor, F extends D> void addCandidatesForExplicitReceiver( 121 @NotNull ReceiverValue receiver, 122 @NotNull List<ReceiverValue> implicitReceivers, 123 @NotNull TaskPrioritizerContext<D, F> c, 124 boolean resolveInvoke 125 ) { 126 127 List<ReceiverValue> variantsForExplicitReceiver = c.autoCastService.getVariantsForReceiver(receiver); 128 129 //members 130 for (CallableDescriptorCollector<? extends D> callableDescriptorCollector : c.callableDescriptorCollectors) { 131 Collection<ResolutionCandidate<D>> members = Lists.newArrayList(); 132 for (ReceiverValue variant : variantsForExplicitReceiver) { 133 Collection<? extends D> membersForThisVariant = callableDescriptorCollector.getMembersByName(variant.getType(), c.name); 134 convertWithReceivers(membersForThisVariant, Collections.singletonList(variant), 135 Collections.singletonList(NO_RECEIVER), members, resolveInvoke); 136 } 137 c.result.addCandidates(members); 138 } 139 140 for (CallableDescriptorCollector<? extends D> callableDescriptorCollector : c.callableDescriptorCollectors) { 141 //member extensions 142 for (ReceiverValue implicitReceiver : implicitReceivers) { 143 addMemberExtensionCandidates(implicitReceiver, variantsForExplicitReceiver, 144 callableDescriptorCollector, c, resolveInvoke); 145 } 146 //extensions 147 Collection<ResolutionCandidate<D>> extensionFunctions = convertWithImpliedThis( 148 c.scope, variantsForExplicitReceiver, callableDescriptorCollector.getNonMembersByName(c.scope, c.name)); 149 c.result.addCandidates(extensionFunctions); 150 } 151 } 152 153 private static <D extends CallableDescriptor, F extends D> void addMemberExtensionCandidates( 154 @NotNull ReceiverValue implicitReceiver, 155 @NotNull List<ReceiverValue> variantsForExplicitReceiver, 156 @NotNull CallableDescriptorCollector<? extends D> callableDescriptorCollector, TaskPrioritizerContext<D, F> c, 157 boolean resolveInvoke 158 ) { 159 Collection<? extends D> memberExtensions = callableDescriptorCollector.getNonMembersByName( 160 implicitReceiver.getType().getMemberScope(), c.name); 161 List<ReceiverValue> variantsForImplicitReceiver = c.autoCastService.getVariantsForReceiver(implicitReceiver); 162 c.result.addCandidates(convertWithReceivers(memberExtensions, variantsForImplicitReceiver, 163 variantsForExplicitReceiver, resolveInvoke)); 164 } 165 166 private static <D extends CallableDescriptor, F extends D> void addCandidatesForNoReceiver( 167 @NotNull List<ReceiverValue> implicitReceivers, 168 @NotNull TaskPrioritizerContext<D, F> c 169 ) { 170 List<Collection<ResolutionCandidate<D>>> localsList = Lists.newArrayList(); 171 List<Collection<ResolutionCandidate<D>>> nonlocalsList = Lists.newArrayList(); 172 for (CallableDescriptorCollector<? extends D> callableDescriptorCollector : c.callableDescriptorCollectors) { 173 174 Collection<ResolutionCandidate<D>> functions = 175 convertWithImpliedThis(c.scope, Collections.singletonList(NO_RECEIVER), callableDescriptorCollector 176 .getNonExtensionsByName(c.scope, c.name)); 177 178 List<ResolutionCandidate<D>> nonlocals = Lists.newArrayList(); 179 List<ResolutionCandidate<D>> locals = Lists.newArrayList(); 180 //noinspection unchecked,RedundantTypeArguments 181 TaskPrioritizer.<D>splitLexicallyLocalDescriptors(functions, c.scope.getContainingDeclaration(), locals, nonlocals); 182 183 localsList.add(locals); 184 nonlocalsList.add(nonlocals); 185 } 186 187 //locals 188 c.result.addCandidates(localsList); 189 190 //try all implicit receivers as explicit 191 for (ReceiverValue implicitReceiver : implicitReceivers) { 192 addCandidatesForExplicitReceiver(implicitReceiver, implicitReceivers, c, /*resolveInvoke=*/false); 193 } 194 195 //nonlocals 196 c.result.addCandidates(nonlocalsList); 197 } 198 199 private static <D extends CallableDescriptor, F extends D> void addCandidatesForInvoke( 200 @NotNull ReceiverValue explicitReceiver, 201 @NotNull TaskPrioritizerContext<D, F> c 202 ) { 203 List<ReceiverValue> implicitReceivers = JetScopeUtils.getImplicitReceiversHierarchyValues(c.scope); 204 205 // For 'a.foo()' where foo has function type, 206 // a is explicitReceiver, foo is variableReceiver. 207 ReceiverValue variableReceiver = c.context.call.getThisObject(); 208 assert variableReceiver.exists() : "'Invoke' call hasn't got variable receiver"; 209 210 // For invocation a.foo() explicit receiver 'a' 211 // can be a receiver for 'foo' variable 212 // or for 'invoke' function. 213 214 // (1) a.foo + foo.invoke() 215 if (!explicitReceiver.exists()) { 216 addCandidatesForExplicitReceiver(variableReceiver, implicitReceivers, c, /*resolveInvoke=*/true); 217 } 218 219 // (2) foo + a.invoke() 220 221 // 'invoke' is member extension to explicit receiver while variable receiver is 'this object' 222 //trait A 223 //trait Foo { fun A.invoke() } 224 225 if (explicitReceiver.exists()) { 226 //a.foo() 227 addCandidatesWhenInvokeIsMemberExtensionToExplicitReceiver(variableReceiver, explicitReceiver, c); 228 return; 229 } 230 // with (a) { foo() } 231 for (ReceiverValue implicitReceiver : implicitReceivers) { 232 addCandidatesWhenInvokeIsMemberExtensionToExplicitReceiver(variableReceiver, implicitReceiver, c); 233 } 234 } 235 236 private static <D extends CallableDescriptor, F extends D> void addCandidatesWhenInvokeIsMemberExtensionToExplicitReceiver( 237 @NotNull ReceiverValue variableReceiver, 238 @NotNull ReceiverValue explicitReceiver, 239 @NotNull TaskPrioritizerContext<D, F> c 240 ) { 241 List<ReceiverValue> variantsForExplicitReceiver = c.autoCastService.getVariantsForReceiver(explicitReceiver); 242 243 for (CallableDescriptorCollector<? extends D> callableDescriptorCollector : c.callableDescriptorCollectors) { 244 addMemberExtensionCandidates(variableReceiver, variantsForExplicitReceiver, callableDescriptorCollector, c, /*resolveInvoke=*/true); 245 } 246 } 247 248 private static <D extends CallableDescriptor> Collection<ResolutionCandidate<D>> convertWithReceivers( 249 @NotNull Collection<? extends D> descriptors, 250 @NotNull Iterable<ReceiverValue> thisObjects, 251 @NotNull Iterable<ReceiverValue> receiverParameters, 252 boolean hasExplicitThisObject 253 ) { 254 Collection<ResolutionCandidate<D>> result = Lists.newArrayList(); 255 convertWithReceivers(descriptors, thisObjects, receiverParameters, result, hasExplicitThisObject); 256 return result; 257 } 258 259 private static <D extends CallableDescriptor> void convertWithReceivers( 260 @NotNull Collection<? extends D> descriptors, 261 @NotNull Iterable<ReceiverValue> thisObjects, 262 @NotNull Iterable<ReceiverValue> receiverParameters, 263 @NotNull Collection<ResolutionCandidate<D>> result, 264 boolean hasExplicitThisObject 265 ) { 266 for (ReceiverValue thisObject : thisObjects) { 267 for (ReceiverValue receiverParameter : receiverParameters) { 268 for (D extension : descriptors) { 269 if (DescriptorUtils.isConstructorOfStaticNestedClass(extension)) { 270 // We don't want static nested classes' constructors to be resolved with expectedThisObject 271 continue; 272 } 273 ResolutionCandidate<D> candidate = ResolutionCandidate.create(extension); 274 candidate.setThisObject(thisObject); 275 candidate.setReceiverArgument(receiverParameter); 276 candidate.setExplicitReceiverKind( 277 hasExplicitThisObject ? ExplicitReceiverKind.BOTH_RECEIVERS : ExplicitReceiverKind.THIS_OBJECT); 278 result.add(candidate); 279 } 280 } 281 } 282 } 283 284 public static <D extends CallableDescriptor> Collection<ResolutionCandidate<D>> convertWithImpliedThis( 285 @NotNull JetScope scope, 286 @NotNull Collection<ReceiverValue> receiverParameters, 287 @NotNull Collection<? extends D> descriptors 288 ) { 289 Collection<ResolutionCandidate<D>> result = Lists.newArrayList(); 290 for (ReceiverValue receiverParameter : receiverParameters) { 291 for (D descriptor : descriptors) { 292 ResolutionCandidate<D> candidate = ResolutionCandidate.create(descriptor); 293 candidate.setReceiverArgument(receiverParameter); 294 candidate.setExplicitReceiverKind( 295 receiverParameter.exists() ? ExplicitReceiverKind.RECEIVER_ARGUMENT : ExplicitReceiverKind.NO_EXPLICIT_RECEIVER); 296 if (setImpliedThis(scope, candidate)) { 297 result.add(candidate); 298 } 299 } 300 } 301 if (receiverParameters.size() == 1 && !receiverParameters.iterator().next().exists()) { 302 for (D descriptor : descriptors) { 303 if (descriptor.getExpectedThisObject() != null && descriptor.getReceiverParameter() == null) { 304 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); 305 if (descriptor instanceof ConstructorDescriptor) { 306 containingDeclaration = containingDeclaration.getContainingDeclaration(); 307 } 308 if (containingDeclaration != null && isClassObject(containingDeclaration)) { 309 ResolutionCandidate<D> candidate = ResolutionCandidate.create(descriptor); 310 candidate.setThisObject(((ClassDescriptor) containingDeclaration).getThisAsReceiverParameter().getValue()); 311 candidate.setExplicitReceiverKind(ExplicitReceiverKind.NO_EXPLICIT_RECEIVER); 312 result.add(candidate); 313 } 314 } 315 } 316 } 317 return result; 318 } 319 320 private static <D extends CallableDescriptor> boolean setImpliedThis( 321 @NotNull JetScope scope, 322 @NotNull ResolutionCandidate<D> candidate 323 ) { 324 ReceiverParameterDescriptor expectedThisObject = candidate.getDescriptor().getExpectedThisObject(); 325 if (expectedThisObject == null) return true; 326 List<ReceiverParameterDescriptor> receivers = scope.getImplicitReceiversHierarchy(); 327 for (ReceiverParameterDescriptor receiver : receivers) { 328 if (JetTypeChecker.INSTANCE.isSubtypeOf(receiver.getType(), expectedThisObject.getType())) { 329 // TODO : Autocasts & nullability 330 candidate.setThisObject(expectedThisObject.getValue()); 331 return true; 332 } 333 } 334 return false; 335 } 336 337 public static <D extends CallableDescriptor, F extends D> List<ResolutionTask<D, F>> computePrioritizedTasksFromCandidates( 338 @NotNull BasicCallResolutionContext context, 339 @NotNull JetReferenceExpression functionReference, 340 @NotNull Collection<ResolutionCandidate<D>> candidates 341 ) { 342 ResolutionTaskHolder<D, F> result = new ResolutionTaskHolder<D, F>(functionReference, context, new MyPriorityProvider<D>(context)); 343 result.addCandidates(candidates); 344 return result.getTasks(); 345 } 346 347 private static class MyPriorityProvider<D extends CallableDescriptor> 348 implements ResolutionTaskHolder.PriorityProvider<ResolutionCandidate<D>> { 349 private final BasicCallResolutionContext context; 350 351 public MyPriorityProvider(BasicCallResolutionContext context) { 352 this.context = context; 353 } 354 355 @Override 356 public int getPriority(ResolutionCandidate<D> call) { 357 return (isVisible(call) ? 2 : 0) + (isSynthesized(call) ? 0 : 1); 358 } 359 360 @Override 361 public int getMaxPriority() { 362 return 3; 363 } 364 365 private boolean isVisible(ResolutionCandidate<D> call) { 366 if (call == null) return false; 367 D candidateDescriptor = call.getDescriptor(); 368 if (ErrorUtils.isError(candidateDescriptor)) return true; 369 return Visibilities.isVisible(candidateDescriptor, context.scope.getContainingDeclaration()); 370 } 371 372 private boolean isSynthesized(ResolutionCandidate<D> call) { 373 D descriptor = call.getDescriptor(); 374 return descriptor instanceof CallableMemberDescriptor && 375 isOrOverridesSynthesized((CallableMemberDescriptor) descriptor); 376 } 377 } 378 379 private static class TaskPrioritizerContext<D extends CallableDescriptor, F extends D> { 380 @NotNull public final Name name; 381 @NotNull public final ResolutionTaskHolder<D, F> result; 382 @NotNull public final BasicCallResolutionContext context; 383 @NotNull public final JetScope scope; 384 @NotNull public final List<CallableDescriptorCollector<? extends D>> callableDescriptorCollectors; 385 @NotNull AutoCastServiceImpl autoCastService; 386 387 private TaskPrioritizerContext( 388 @NotNull Name name, 389 @NotNull ResolutionTaskHolder<D, F> result, 390 @NotNull BasicCallResolutionContext context, 391 @NotNull JetScope scope, 392 @NotNull List<CallableDescriptorCollector<? extends D>> callableDescriptorCollectors 393 ) { 394 this.name = name; 395 this.result = result; 396 this.context = context; 397 this.scope = scope; 398 this.callableDescriptorCollectors = callableDescriptorCollectors; 399 autoCastService = new AutoCastServiceImpl(context.dataFlowInfo, context.trace.getBindingContext()); 400 } 401 } 402}