/* * Copyright (c) 2012, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.engine.internal.type; import com.google.dart.engine.element.TypeParameterElement; import com.google.dart.engine.internal.element.ElementPair; import com.google.dart.engine.type.Type; import com.google.dart.engine.type.TypeParameterType; import com.google.dart.engine.utilities.general.ObjectUtilities; import java.util.HashSet; import java.util.Set; /** * Instances of the class {@code TypeParameterTypeImpl} defines the behavior of objects representing * the type introduced by a type parameter. * * @coverage dart.engine.type */ public class TypeParameterTypeImpl extends TypeImpl implements TypeParameterType { /** * An empty array of type parameter types. */ public static final TypeParameterType[] EMPTY_ARRAY = new TypeParameterType[0]; /** * Return an array containing the type parameter types defined by the given array of type * parameter elements. * * @param typeParameters the type parameter elements defining the type parameter types to be * returned * @return the type parameter types defined by the type parameter elements */ public static TypeParameterType[] getTypes(TypeParameterElement[] typeParameters) { int count = typeParameters.length; if (count == 0) { return EMPTY_ARRAY; } TypeParameterType[] types = new TypeParameterType[count]; for (int i = 0; i < count; i++) { types[i] = typeParameters[i].getType(); } return types; } /** * Initialize a newly created type parameter type to be declared by the given element and to have * the given name. * * @param element the element representing the declaration of the type parameter */ public TypeParameterTypeImpl(TypeParameterElement element) { super(element, element.getName()); } @Override public boolean equals(Object object) { return object instanceof TypeParameterTypeImpl && ObjectUtilities.equals(getElement(), ((TypeParameterTypeImpl) object).getElement()); } @Override public TypeParameterElement getElement() { return (TypeParameterElement) super.getElement(); } @Override public int hashCode() { return getElement().hashCode(); } @Override public Type substitute(Type[] argumentTypes, Type[] parameterTypes) { int length = parameterTypes.length; for (int i = 0; i < length; i++) { if (parameterTypes[i].equals(this)) { return argumentTypes[i]; } } return this; } @Override protected boolean internalEquals(Object object, Set<ElementPair> visitedElementPairs) { return equals(object); } @Override protected boolean internalIsMoreSpecificThan(Type s, boolean withDynamic, Set<TypePair> visitedTypePairs) { // // A type T is more specific than a type S, written T << S, if one of the following conditions // is met: // // Reflexivity: T is S. // if (this.equals(s)) { return true; } // S is dynamic. // if (s.isDynamic()) { return true; } return isMoreSpecificThan(s, new HashSet<Type>(), withDynamic, visitedTypePairs); } @Override protected boolean internalIsSubtypeOf(Type type, Set<TypePair> visitedTypePairs) { return isMoreSpecificThan(type, true, new HashSet<TypePair>()); } private boolean isMoreSpecificThan(Type s, Set<Type> visitedTypes, boolean withDynamic, Set<TypePair> visitedTypePairs) { // // T is a type parameter and S is the upper bound of T. // Type bound = getElement().getBound(); if (s.equals(bound)) { return true; } // // T is a type parameter and S is Object. // if (s.isObject()) { return true; } // We need upper bound to continue. if (bound == null) { return false; } // // Transitivity: T << U and U << S. // if (bound instanceof TypeParameterTypeImpl) { TypeParameterTypeImpl boundTypeParameter = (TypeParameterTypeImpl) bound; // First check for infinite loops if (visitedTypes.contains(bound)) { return false; } visitedTypes.add(bound); // Then check upper bound. return boundTypeParameter.isMoreSpecificThan(s, visitedTypes, withDynamic, visitedTypePairs); } // Check interface type. return ((TypeImpl) bound).isMoreSpecificThan(s, withDynamic, visitedTypePairs); } }