@Override public FunctionTypeImpl substitute(Type[] argumentTypes, Type[] parameterTypes) { if (argumentTypes.length != parameterTypes.length) { throw new IllegalArgumentException( "argumentTypes.length (" + argumentTypes.length + ") != parameterTypes.length (" + parameterTypes.length + ")"); } if (argumentTypes.length == 0) { return this; } Element element = getElement(); FunctionTypeImpl newType = (element instanceof ExecutableElement) ? new FunctionTypeImpl((ExecutableElement) element) : new FunctionTypeImpl((FunctionTypeAliasElement) element); newType.setReturnType(returnType.substitute(argumentTypes, parameterTypes)); newType.setNormalParameterTypes( substitute(normalParameterTypes, argumentTypes, parameterTypes)); newType.setOptionalParameterTypes( substitute(optionalParameterTypes, argumentTypes, parameterTypes)); newType.namedParameterTypes = substitute(namedParameterTypes, argumentTypes, parameterTypes); return newType; }
/** * Determine whether the given field's type is changed when type parameters from the defining * type's declaration are replaced with the actual type arguments from the defining type. * * @param baseField the base field * @param definingType the type defining the parameters and arguments to be used in the * substitution * @return true if the type is changed by type substitution. */ private static boolean isChangedByTypeSubstitution( FieldElement baseField, InterfaceType definingType) { Type[] argumentTypes = definingType.getTypeArguments(); if (baseField != null && argumentTypes.length != 0) { Type baseType = baseField.getType(); Type[] parameterTypes = definingType.getElement().getType().getTypeArguments(); if (baseType != null) { Type substitutedType = baseType.substitute(argumentTypes, parameterTypes); if (!baseType.equals(substitutedType)) { return true; } } // If the field has a propagated type, then we need to check whether the propagated type // needs substitution. Type basePropagatedType = baseField.getPropagatedType(); if (basePropagatedType != null) { Type substitutedPropagatedType = basePropagatedType.substitute(argumentTypes, parameterTypes); if (!basePropagatedType.equals(substitutedPropagatedType)) { return true; } } } return false; }
@Override public boolean isSubtypeOf(Type type) { // trivial base cases if (type == null) { return false; } else if (this == type || type.isDynamic() || type.isDartCoreFunction()) { return true; } else if (!(type instanceof FunctionType)) { return false; } else if (this.equals(type)) { return true; } FunctionType t = this; FunctionType s = (FunctionType) type; // normal parameter types if (t.getNormalParameterTypes().length != s.getNormalParameterTypes().length) { return false; } else if (t.getNormalParameterTypes().length > 0) { Type[] tTypes = t.getNormalParameterTypes(); Type[] sTypes = s.getNormalParameterTypes(); for (int i = 0; i < tTypes.length; i++) { if (!tTypes[i].isAssignableTo(sTypes[i])) { return false; } } } // optional parameter types if (t.getOptionalParameterTypes().length > 0) { Type[] tOpTypes = t.getOptionalParameterTypes(); Type[] sOpTypes = s.getOptionalParameterTypes(); // if k >= m is false, return false: the passed function type has more optional parameter // types than this if (tOpTypes.length < sOpTypes.length) { return false; } for (int i = 0; i < sOpTypes.length; i++) { if (!tOpTypes[i].isAssignableTo(sOpTypes[i])) { return false; } } if (t.getNamedParameterTypes().size() > 0 || s.getNamedParameterTypes().size() > 0) { return false; } } else if (s.getOptionalParameterTypes().length > 0) { return false; } // named parameter types if (t.getNamedParameterTypes().size() > 0) { Map<String, Type> namedTypesT = t.getNamedParameterTypes(); Map<String, Type> namedTypesS = s.getNamedParameterTypes(); // if k >= m is false, return false: the passed function type has more named parameter types // than this if (namedTypesT.size() < namedTypesS.size()) { return false; } // Loop through each element in S verifying that T has a matching parameter name and that the // corresponding type is assignable to the type in S. Iterator<Entry<String, Type>> iteratorS = namedTypesS.entrySet().iterator(); while (iteratorS.hasNext()) { Entry<String, Type> entryS = iteratorS.next(); Type typeT = namedTypesT.get(entryS.getKey()); if (typeT == null) { return false; } if (!entryS.getValue().isAssignableTo(typeT)) { return false; } } } else if (s.getNamedParameterTypes().size() > 0) { return false; } return s.getReturnType().equals(VoidTypeImpl.getInstance()) || t.getReturnType().isAssignableTo(s.getReturnType()); }