001 /*
002 * Copyright 2010-2015 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
017 package org.jetbrains.kotlin.resolve.calls.results;
018
019 import org.jetbrains.annotations.NotNull;
020
021 import java.util.EnumSet;
022
023 public enum ResolutionStatus {
024 UNKNOWN_STATUS,
025 UNSAFE_CALL_ERROR,
026 OTHER_ERROR,
027 ARGUMENTS_MAPPING_ERROR,
028 // '1.foo()' shouldn't be resolved to 'fun String.foo()'
029 // candidates with such error are treated specially
030 // (are mentioned in 'unresolved' error, if there are no other options)
031 RECEIVER_TYPE_ERROR,
032 // 'a.foo()' shouldn't be resolved to package level non-extension 'fun foo()'
033 // candidates with such error are thrown away completely
034 RECEIVER_PRESENCE_ERROR,
035 INCOMPLETE_TYPE_INFERENCE,
036 SUCCESS(true);
037
038 @SuppressWarnings("unchecked")
039 public static final EnumSet<ResolutionStatus>[] SEVERITY_LEVELS = new EnumSet[] {
040 EnumSet.of(UNSAFE_CALL_ERROR), // weakest
041 EnumSet.of(OTHER_ERROR),
042 EnumSet.of(ARGUMENTS_MAPPING_ERROR),
043 EnumSet.of(RECEIVER_TYPE_ERROR),
044 EnumSet.of(RECEIVER_PRESENCE_ERROR), // most severe
045 };
046
047 private final boolean success;
048 private int severityIndex = -1;
049
050 private ResolutionStatus(boolean success) {
051 this.success = success;
052 }
053
054 private ResolutionStatus() {
055 this(false);
056 }
057
058 public boolean isSuccess() {
059 return success;
060 }
061
062 public boolean possibleTransformToSuccess() {
063 return this == UNKNOWN_STATUS || this == INCOMPLETE_TYPE_INFERENCE || this == SUCCESS;
064 }
065
066 @NotNull
067 public ResolutionStatus combine(ResolutionStatus other) {
068 if (this == UNKNOWN_STATUS) return other;
069 if (SUCCESS.among(this, other)) {
070 return SUCCESS.chooseDifferent(this, other);
071 }
072 if (INCOMPLETE_TYPE_INFERENCE.among(this, other)) {
073 return INCOMPLETE_TYPE_INFERENCE.chooseDifferent(this, other);
074 }
075 if (this.getSeverityIndex() < other.getSeverityIndex()) return other;
076 return this;
077 }
078
079 private boolean among(ResolutionStatus first, ResolutionStatus second) {
080 return this == first || this == second;
081 }
082
083 private ResolutionStatus chooseDifferent(ResolutionStatus first, ResolutionStatus second) {
084 assert among(first, second);
085 return this == first ? second : first;
086 }
087
088 private int getSeverityIndex() {
089 if (severityIndex == -1) {
090 for (int i = 0; i < SEVERITY_LEVELS.length; i++) {
091 if (SEVERITY_LEVELS[i].contains(this)) {
092 severityIndex = i;
093 break;
094 }
095 }
096 }
097 assert severityIndex >= 0;
098
099 return severityIndex;
100 }
101 }