isCompatibleReplacement method

bool isCompatibleReplacement({
  1. required TypeIdentifier oldTypeIdentifier,
  2. required TypeIdentifier newTypeIdentifier,
  3. required bool isTypePassedIn,
})

checks if newTypeIdentifier is a compatible replacement for oldTypeIdentifier

Implementation

bool isCompatibleReplacement({
  required TypeIdentifier oldTypeIdentifier,
  required TypeIdentifier newTypeIdentifier,
  required bool isTypePassedIn,
}) {
  if (isTypePassedIn) {
    // for types passed in: dynamic and Object? are equivalent and compatible to whatever has been there before
    if (newTypeIdentifier.isDynamic) {
      return true;
    }
    if (newTypeIdentifier.typeName == 'Object?') {
      return true;
    }
  } else {
    // for types returned changing from anything to dynamic is compatible
    if (newTypeIdentifier.isDynamic) {
      return true;
    }
  }
  // if we try to replace a nullable type with a non-nullable for types passed in then we can return early
  if (isTypePassedIn &&
      !newTypeIdentifier.isNullable &&
      oldTypeIdentifier.isNullable) {
    return false;
  }
  // if we try to replace a non-nullable type with a nullable for types passed out then we can return early
  if (!isTypePassedIn &&
      newTypeIdentifier.isNullable &&
      !oldTypeIdentifier.isNullable) {
    return false;
  }

  // and then compare the types without Nullable
  oldTypeIdentifier = oldTypeIdentifier.asNonNullable();
  newTypeIdentifier = newTypeIdentifier.asNonNullable();

  /// if the names and packages are equal we consider them to be equal
  if (oldTypeIdentifier.packageAndTypeName ==
      newTypeIdentifier.packageAndTypeName) {
    return true;
  }

  final newIsSubtypeOfOld =
      _isSubTypeOf(newTypeIdentifier, oldTypeIdentifier);
  final oldIsSubtypeOfNew =
      _isSubTypeOf(oldTypeIdentifier, newTypeIdentifier);

  // if we pass the type in then it can get wider
  // if we pass it out then it can get narrower
  return isTypePassedIn ? oldIsSubtypeOfNew : newIsSubtypeOfOld;
}