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.types; 018 019import com.google.common.collect.Lists; 020import com.google.common.collect.Sets; 021import org.jetbrains.annotations.NotNull; 022import org.jetbrains.jet.lang.descriptors.ClassDescriptor; 023import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; 024import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; 025import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; 026import org.jetbrains.jet.lang.resolve.scopes.JetScope; 027import org.jetbrains.jet.lang.types.checker.JetTypeChecker; 028import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 029import org.jetbrains.jet.utils.DFS; 030 031import java.util.*; 032 033import static org.jetbrains.jet.lang.types.Variance.*; 034 035public class CommonSupertypes { 036 @NotNull 037 public static JetType commonSupertype(@NotNull Collection<JetType> types) { 038 Collection<JetType> typeSet = new HashSet<JetType>(types); 039 assert !typeSet.isEmpty(); 040 041 // If any of the types is nullable, the result must be nullable 042 // This also removed Nothing and Nothing? because they are subtypes of everything else 043 boolean nullable = false; 044 for (Iterator<JetType> iterator = typeSet.iterator(); iterator.hasNext();) { 045 JetType type = iterator.next(); 046 assert type != null; 047 if (KotlinBuiltIns.getInstance().isNothingOrNullableNothing(type)) { 048 iterator.remove(); 049 } 050 if (ErrorUtils.isErrorType(type)) { 051 return ErrorUtils.createErrorType("Supertype of error type " + type); 052 } 053 nullable |= type.isNullable(); 054 } 055 056 // Everything deleted => it's Nothing or Nothing? 057 if (typeSet.isEmpty()) { 058 // TODO : attributes 059 return nullable ? KotlinBuiltIns.getInstance().getNullableNothingType() : KotlinBuiltIns.getInstance().getNothingType(); 060 } 061 062 if (typeSet.size() == 1) { 063 return TypeUtils.makeNullableIfNeeded(typeSet.iterator().next(), nullable); 064 } 065 066 // constructor of the supertype -> all of its instantiations occurring as supertypes 067 Map<TypeConstructor, Set<JetType>> commonSupertypes = computeCommonRawSupertypes(typeSet); 068 while (commonSupertypes.size() > 1) { 069 Set<JetType> merge = new HashSet<JetType>(); 070 for (Set<JetType> supertypes : commonSupertypes.values()) { 071 merge.addAll(supertypes); 072 } 073 commonSupertypes = computeCommonRawSupertypes(merge); 074 } 075 assert !commonSupertypes.isEmpty() : commonSupertypes + " <- " + types; 076 077 // constructor of the supertype -> all of its instantiations occurring as supertypes 078 Map.Entry<TypeConstructor, Set<JetType>> entry = commonSupertypes.entrySet().iterator().next(); 079 080 // Reconstructing type arguments if possible 081 JetType result = computeSupertypeProjections(entry.getKey(), entry.getValue()); 082 return TypeUtils.makeNullableIfNeeded(result, nullable); 083 } 084 085 // Raw supertypes are superclasses w/o type arguments 086 // @return TypeConstructor -> all instantiations of this constructor occurring as supertypes 087 @NotNull 088 private static Map<TypeConstructor, Set<JetType>> computeCommonRawSupertypes(@NotNull Collection<JetType> types) { 089 assert !types.isEmpty(); 090 091 Map<TypeConstructor, Set<JetType>> constructorToAllInstances = new HashMap<TypeConstructor, Set<JetType>>(); 092 Set<TypeConstructor> commonSuperclasses = null; 093 094 List<TypeConstructor> order = null; 095 for (JetType type : types) { 096 Set<TypeConstructor> visited = Sets.newHashSet(); 097 order = topologicallySortSuperclassesAndRecordAllInstances(type, constructorToAllInstances, visited); 098 099 if (commonSuperclasses == null) { 100 commonSuperclasses = visited; 101 } 102 else { 103 commonSuperclasses.retainAll(visited); 104 } 105 } 106 assert order != null; 107 108 Set<TypeConstructor> notSource = new HashSet<TypeConstructor>(); 109 Map<TypeConstructor, Set<JetType>> result = new HashMap<TypeConstructor, Set<JetType>>(); 110 for (TypeConstructor superConstructor : order) { 111 if (!commonSuperclasses.contains(superConstructor)) { 112 continue; 113 } 114 115 if (!notSource.contains(superConstructor)) { 116 result.put(superConstructor, constructorToAllInstances.get(superConstructor)); 117 markAll(superConstructor, notSource); 118 } 119 } 120 121 return result; 122 } 123 124 private static List<TypeConstructor> topologicallySortSuperclassesAndRecordAllInstances( 125 @NotNull JetType type, 126 @NotNull final Map<TypeConstructor, Set<JetType>> constructorToAllInstances, 127 @NotNull final Set<TypeConstructor> visited 128 ) { 129 return DFS.dfs( 130 Collections.singletonList(type), 131 new DFS.Neighbors<JetType>() { 132 @NotNull 133 @Override 134 public Iterable<JetType> getNeighbors(JetType current) { 135 TypeSubstitutor substitutor = TypeSubstitutor.create(current); 136 List<JetType> result = Lists.newArrayList(); 137 for (JetType supertype : current.getConstructor().getSupertypes()) { 138 if (visited.contains(supertype.getConstructor())) { 139 continue; 140 } 141 result.add(substitutor.safeSubstitute(supertype, INVARIANT)); 142 } 143 return result; 144 } 145 }, 146 new DFS.Visited<JetType>() { 147 @Override 148 public boolean checkAndMarkVisited(JetType current) { 149 return visited.add(current.getConstructor()); 150 } 151 }, 152 new DFS.NodeHandlerWithListResult<JetType, TypeConstructor>() { 153 @Override 154 public void beforeChildren(JetType current) { 155 TypeConstructor constructor = current.getConstructor(); 156 157 Set<JetType> instances = constructorToAllInstances.get(constructor); 158 if (instances == null) { 159 instances = new HashSet<JetType>(); 160 constructorToAllInstances.put(constructor, instances); 161 } 162 instances.add(current); 163 } 164 165 @Override 166 public void afterChildren(JetType current) { 167 result.addFirst(current.getConstructor()); 168 } 169 } 170 ); 171 } 172 173 // constructor - type constructor of a supertype to be instantiated 174 // types - instantiations of constructor occurring as supertypes of classes we are trying to intersect 175 @NotNull 176 private static JetType computeSupertypeProjections(@NotNull TypeConstructor constructor, @NotNull Set<JetType> types) { 177 // we assume that all the given types are applications of the same type constructor 178 179 assert !types.isEmpty(); 180 181 if (types.size() == 1) { 182 return types.iterator().next(); 183 } 184 185 List<TypeParameterDescriptor> parameters = constructor.getParameters(); 186 List<TypeProjection> newProjections = new ArrayList<TypeProjection>(); 187 for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) { 188 TypeParameterDescriptor parameterDescriptor = parameters.get(i); 189 Set<TypeProjection> typeProjections = new HashSet<TypeProjection>(); 190 for (JetType type : types) { 191 typeProjections.add(type.getArguments().get(i)); 192 } 193 newProjections.add(computeSupertypeProjection(parameterDescriptor, typeProjections)); 194 } 195 196 boolean nullable = false; 197 for (JetType type : types) { 198 nullable |= type.isNullable(); 199 } 200 201 // TODO : attributes? 202 JetScope newScope = KotlinBuiltIns.getInstance().STUB; 203 DeclarationDescriptor declarationDescriptor = constructor.getDeclarationDescriptor(); 204 if (declarationDescriptor instanceof ClassDescriptor) { 205 newScope = ((ClassDescriptor) declarationDescriptor).getMemberScope(newProjections); 206 } 207 return new JetTypeImpl(Collections.<AnnotationDescriptor>emptyList(), constructor, nullable, newProjections, newScope); 208 } 209 210 @NotNull 211 private static TypeProjection computeSupertypeProjection(@NotNull TypeParameterDescriptor parameterDescriptor, @NotNull Set<TypeProjection> typeProjections) { 212 if (typeProjections.size() == 1) { 213 return typeProjections.iterator().next(); 214 } 215 216 Set<JetType> ins = new HashSet<JetType>(); 217 Set<JetType> outs = new HashSet<JetType>(); 218 219 Variance variance = parameterDescriptor.getVariance(); 220 switch (variance) { 221 case INVARIANT: 222 // Nothing 223 break; 224 case IN_VARIANCE: 225 outs = null; 226 break; 227 case OUT_VARIANCE: 228 ins = null; 229 break; 230 } 231 232 for (TypeProjection projection : typeProjections) { 233 Variance projectionKind = projection.getProjectionKind(); 234 if (projectionKind.allowsInPosition()) { 235 if (ins != null) { 236 ins.add(projection.getType()); 237 } 238 } 239 else { 240 ins = null; 241 } 242 243 if (projectionKind.allowsOutPosition()) { 244 if (outs != null) { 245 outs.add(projection.getType()); 246 } 247 } 248 else { 249 outs = null; 250 } 251 } 252 253 if (ins != null) { 254 JetType intersection = TypeUtils.intersect(JetTypeChecker.INSTANCE, ins); 255 if (intersection == null) { 256 if (outs != null) { 257 return new TypeProjection(OUT_VARIANCE, commonSupertype(outs)); 258 } 259 return new TypeProjection(OUT_VARIANCE, commonSupertype(parameterDescriptor.getUpperBounds())); 260 } 261 Variance projectionKind = variance == IN_VARIANCE ? Variance.INVARIANT : IN_VARIANCE; 262 return new TypeProjection(projectionKind, intersection); 263 } 264 else if (outs != null) { 265 Variance projectionKind = variance == OUT_VARIANCE ? Variance.INVARIANT : OUT_VARIANCE; 266 return new TypeProjection(projectionKind, commonSupertype(outs)); 267 } 268 else { 269 Variance projectionKind = variance == OUT_VARIANCE ? Variance.INVARIANT : OUT_VARIANCE; 270 return new TypeProjection(projectionKind, commonSupertype(parameterDescriptor.getUpperBounds())); 271 } 272 } 273 274 private static void markAll(@NotNull TypeConstructor typeConstructor, @NotNull Set<TypeConstructor> markerSet) { 275 markerSet.add(typeConstructor); 276 for (JetType type : typeConstructor.getSupertypes()) { 277 markAll(type.getConstructor(), markerSet); 278 } 279 } 280}