///|
fn is_listing_property_name(name : String) -> Bool {
  match name {
    "length"
    | "isEmpty"
    // PKL-148: PKL-base Listing properties — `isNotEmpty`, `isDistinct`,
    // `firstOrNull`, `lastOrNull`, `toList`, `toSet`. Apple Pkl projects
    // them as zero-arg property reads (no parens) since the underlying
    // method has no parameters.
    | "isNotEmpty"
    | "isDistinct"
    | "firstOrNull"
    | "lastOrNull"
    | "restOrNull"
    | "singleOrNull"
    | "toList"
    | "toSet"
    | "toListing"
    | "first"
    | "last"
    | "distinct"
    // PKL-151: pkl:base Listing/List extra property surface from
    // api/list.pkl. `single` raises unless length == 1; `rest` drops
    // the head; `lastIndex` is `length - 1`. `min` / `max` raise on
    // empty or non-comparable inputs.
    | "single"
    | "rest"
    | "lastIndex"
    | "min"
    | "max"
    | "minOrNull"
    | "maxOrNull"
    // PKL-151: read-only conversions Apple Pkl exposes as properties.
    | "flatten"
    | "filterNonNull" => true
    _ => false
  }
}

///|
fn is_listing_method_name(name : String) -> Bool {
  match name {
    "contains"
    | "fold"
    | "map"
    | "filter"
    | "take"
    | "drop"
    | "join"
    | "reverse"
    // PKL-148: pkl:base Listing surface — `getOrNull(idx)`,
    // `startsWith(other)`, `endsWith(other)`, `min` / `max` / `sum`.
    | "getOrNull"
    | "getOrDefault"
    | "startsWith"
    | "endsWith"
    // PKL-148b: Listing.isDistinctBy(keyFn) — checks whether elements
    // are unique under the key extractor.
    | "isDistinctBy"
    // PKL-134: read-only conversion methods used by pkf / pkspec's
    // shape inspection chains (`tests.toList().map(...)`).
    | "toList"
    | "toMap"
    // PKL-135: predicate / search / flatten methods used by pkspec's
    // `tagSteps`, `duplicateNames`, and rendered Mapping projections.
    | "flatMap"
    | "count"
    | "every"
    | "any"
    | "none"
    | "find"
    | "findOrNull"
    | "findLast"
    | "findLastOrNull"
    | "indexOfOrNull"
    | "lastIndexOfOrNull"
    | "findIndexOrNull"
    | "findLastIndexOrNull"
    // Apple Pkl exposes the no-arg surface (`toSet`, `toListing`,
    // `first`, `last`, `firstOrNull`, `lastOrNull`, `distinct`,
    // `isEmpty`, `isNotEmpty`, `isDistinct`) as both property reads
    // and method calls; accept the `()` form too so fixtures like
    // `list.toSet()` route through the method dispatcher.
    | "toSet"
    | "toListing"
    | "first"
    | "last"
    | "firstOrNull"
    | "lastOrNull"
    | "restOrNull"
    | "singleOrNull"
    | "distinct"
    | "isEmpty"
    | "isNotEmpty"
    | "isDistinct"
    // PKL-151: extended Listing method surface from api/list.pkl.
    | "single"
    | "rest"
    | "lastIndex"
    | "min"
    | "max"
    | "minOrNull"
    | "maxOrNull"
    | "flatten"
    | "filterNonNull"
    | "sort"
    | "sortBy"
    | "sortWith"
    | "minBy"
    | "maxBy"
    | "minByOrNull"
    | "maxByOrNull"
    | "minWith"
    | "maxWith"
    | "minWithOrNull"
    | "maxWithOrNull"
    | "distinctBy"
    | "indexOf"
    | "lastIndexOf"
    | "findIndex"
    | "findLastIndex"
    | "takeWhile"
    | "takeLast"
    | "takeLastWhile"
    | "dropWhile"
    | "dropLast"
    | "dropLastWhile"
    | "repeat"
    | "reduce"
    | "reduceOrNull"
    | "foldBack"
    | "groupBy"
    | "partition"
    | "split"
    | "splitOrNull"
    | "sublistOrNull"
    | "replace"
    | "replaceOrNull"
    | "replaceRange"
    | "replaceRangeOrNull"
    | "add"
    | "zip"
    | "filterIndexed"
    | "mapIndexed"
    | "foldIndexed"
    | "flatMapIndexed"
    | "mapNonNull"
    | "mapNonNullIndexed"
    | "filterIsInstance"
    | "toDynamic"
    | "toBytes" => true
    _ => false
  }
}

///|
fn eval_listing_property(
  elements : Array[Value],
  name : String,
  diagnostics : Array[Diagnostic],
) -> Value? {
  match name {
    "length" => Some(IntValue(elements.length().to_int64()))
    "isEmpty" => Some(BoolValue(elements.length() == 0))
    "isNotEmpty" => Some(BoolValue(elements.length() != 0))
    "isDistinct" => {
      let seen : Array[Value] = []
      let mut distinct = true
      for v in elements {
        if contains_value(seen, v) {
          distinct = false
          break
        }
        seen.push(v)
      }
      Some(BoolValue(distinct))
    }
    "firstOrNull" =>
      if elements.length() == 0 {
        Some(NullValue)
      } else {
        value_or_top_level_deferred_diagnostic(elements[0], diagnostics)
      }
    "lastOrNull" =>
      if elements.length() == 0 {
        Some(NullValue)
      } else {
        value_or_top_level_deferred_diagnostic(
          elements[elements.length() - 1],
          diagnostics,
        )
      }
    "restOrNull" =>
      if elements.length() == 0 {
        Some(NullValue)
      } else {
        Some(ListingValue(list_slice(elements, 1, elements.length())))
      }
    "singleOrNull" =>
      if elements.length() == 1 {
        Some(elements[0])
      } else {
        Some(NullValue)
      }
    // PKL-148h: `.toList()` tags as `ListValue` (round-trips through
    // the `List(...)` constructor form); `.toListing()` keeps the
    // Listing block tag. `.toSet` deduplicates and tags as Set.
    "toList" => {
      match first_deferred_error_message(ListingValue(elements)) {
        Some(message) => {
          diagnostics.push(diag(message))
          return None
        }
        None => ()
      }
      Some(ListValue(elements))
    }
    "toListing" => Some(ListingValue(elements))
    "toSet" => {
      let seen : Array[Value] = []
      for v in elements {
        if !contains_value(seen, v) {
          seen.push(v)
        }
      }
      Some(SetValue(seen))
    }
    "first" =>
      if elements.length() == 0 {
        diagnostics.push(diag("Expected a non-empty Listing."))
        None
      } else {
        value_or_top_level_deferred_diagnostic(elements[0], diagnostics)
      }
    "last" =>
      if elements.length() == 0 {
        diagnostics.push(diag("Expected a non-empty Listing."))
        None
      } else {
        value_or_top_level_deferred_diagnostic(
          elements[elements.length() - 1],
          diagnostics,
        )
      }
    "distinct" => {
      let seen : Array[Value] = []
      for v in elements {
        if !contains_value(seen, v) {
          seen.push(v)
        }
      }
      Some(ListingValue(seen))
    }
    // PKL-151: `single` returns the only element; raises on length != 1.
    "single" =>
      if elements.length() == 1 {
        Some(elements[0])
      } else {
        diagnostics.push(diag("Expected a single-element Listing."))
        None
      }
    // PKL-151: `rest` drops the head element. Empty input raises.
    "rest" =>
      if elements.length() == 0 {
        diagnostics.push(diag("Cannot take the rest of an empty collection."))
        None
      } else {
        let out : Array[Value] = []
        for i = 1; i < elements.length(); i = i + 1 {
          out.push(elements[i])
        }
        Some(ListingValue(out))
      }
    // PKL-151: `lastIndex` mirrors Apple Pkl's `length - 1` semantics
    // (returns `-1` on empty input, the same convention `String` uses).
    "lastIndex" => Some(IntValue((elements.length() - 1).to_int64()))
    // PKL-151: `min` / `max` use Pkl ordering — Int/Float/String all
    // support `<` / `>` via the value model's compare operator. Empty
    // input raises.
    "min" =>
      if elements.length() == 0 {
        diagnostics.push(diag(collection_non_empty_message(elements)))
        None
      } else {
        let mut acc = elements[0]
        for i = 1; i < elements.length(); i = i + 1 {
          let cmp = compare_values(elements[i], acc)
          if cmp == incomparable_value_ordering_sentinel() {
            diagnostics.push(
              diag(
                undefined_operator_for_operand_types_message(
                  LessThan,
                  elements[i],
                  acc,
                ),
              ),
            )
            return None
          }
          if cmp < 0 {
            acc = elements[i]
          }
        }
        Some(acc)
      }
    "max" =>
      if elements.length() == 0 {
        diagnostics.push(diag(collection_non_empty_message(elements)))
        None
      } else {
        let mut acc = elements[0]
        for i = 1; i < elements.length(); i = i + 1 {
          let cmp = compare_values(elements[i], acc)
          if cmp == incomparable_value_ordering_sentinel() {
            diagnostics.push(
              diag(
                undefined_operator_for_operand_types_message(
                  GreaterThan,
                  elements[i],
                  acc,
                ),
              ),
            )
            return None
          }
          if cmp > 0 {
            acc = elements[i]
          }
        }
        Some(acc)
      }
    "minOrNull" =>
      if elements.length() == 0 {
        Some(NullValue)
      } else {
        eval_listing_property(elements, "min", diagnostics)
      }
    "maxOrNull" =>
      if elements.length() == 0 {
        Some(NullValue)
      } else {
        eval_listing_property(elements, "max", diagnostics)
      }
    // PKL-151: `flatten` concatenates the inner Listing/List elements
    // into a single Listing. Non-collection elements are an error.
    "flatten" => {
      let out : Array[Value] = []
      for v in elements {
        match v {
          ListingValue(xs) | ListValue(xs) | SetValue(xs) =>
            for x in xs {
              out.push(x)
            }
          _ => {
            diagnostics.push(
              diag(
                "Listing.flatten expects each element to be a Listing / List / Set.",
              ),
            )
            return None
          }
        }
      }
      Some(ListingValue(out))
    }
    // PKL-151: `filterNonNull` strips NullValue elements.
    "filterNonNull" => {
      let out : Array[Value] = []
      for v in elements {
        if !(v is NullValue) {
          out.push(v)
        }
      }
      Some(ListingValue(out))
    }
    _ => None
  }
}

///|
fn incomparable_value_ordering_sentinel() -> Int {
  -2
}

///|
/// PKL-151: compare two scalar values for ordering. Returns -1 / 0 / +1.
/// Mismatched types raise via -2 sentinel; callers should diagnostic +
/// bail. Only the comparable scalars Apple Pkl supports for min / max
/// (Int / Float / String / Duration / DataSize) are handled; anything
/// else is treated as "incomparable" and bails.
fn compare_values(a : Value, b : Value) -> Int {
  match (a, b) {
    (IntValue(x), IntValue(y)) => if x < y { -1 } else if x > y { 1 } else { 0 }
    (FloatValue(x), FloatValue(y)) =>
      if x < y {
        -1
      } else if x > y {
        1
      } else {
        0
      }
    (IntValue(x), FloatValue(y)) => {
      let xf = x.to_double()
      if xf < y {
        -1
      } else if xf > y {
        1
      } else {
        0
      }
    }
    (FloatValue(x), IntValue(y)) => {
      let yf = y.to_double()
      if x < yf {
        -1
      } else if x > yf {
        1
      } else {
        0
      }
    }
    (StringValue(x), StringValue(y)) => x.lexical_compare(y)
    (DurationValue(xv, xu), DurationValue(yv, yu)) => {
      // Normalize to nanoseconds via the existing helper for ordering.
      let xn = duration_to_ns(xv, xu)
      let yn = duration_to_ns(yv, yu)
      if xn < yn {
        -1
      } else if xn > yn {
        1
      } else {
        0
      }
    }
    (DataSizeValue(xv, xu), DataSizeValue(yv, yu)) => {
      let xn = datasize_to_bytes(xv, xu)
      let yn = datasize_to_bytes(yv, yu)
      if xn < yn {
        -1
      } else if xn > yn {
        1
      } else {
        0
      }
    }
    _ => incomparable_value_ordering_sentinel()
  }
}

///|
fn pkl_bool_return_type_message(value : Value) -> String {
  "Expected value of type `Boolean`, but got type `\{eval_value_type_name(value)}`. Value: \{render_pcf_value_inline(value)}"
}

///|
fn pkl_collection_return_type_message(value : Value) -> String {
  "Expected value of type `Collection`, but got type `\{eval_value_type_name(value)}`. Value: \{render_pcf_value_inline(value)}"
}

///|
fn list_slice(elements : Array[Value], start : Int, end : Int) -> Array[Value] {
  let out : Array[Value] = []
  for i = start; i < end; i = i + 1 {
    out.push(elements[i])
  }
  out
}

///|
fn collection_index_range_message(
  index : Int64,
  lower : Int,
  upper : Int,
  elements : Array[Value],
) -> String {
  "Element index `\{index}` is out of range `\{lower}`..`\{upper}`. Collection: \{render_pcf_value_inline(ListValue(elements))}"
}

///|
fn collection_non_empty_message(elements : Array[Value]) -> String {
  "Expected a non-empty collection. Collection: \{render_pcf_value_inline(ListValue(elements))}"
}

///|
fn unique_values(values : Array[Value]) -> Array[Value] {
  let out : Array[Value] = []
  for value in values {
    if !contains_value(out, value) {
      out.push(value)
    }
  }
  out
}

///|
fn dynamic_from_elements(elements : Array[Value]) -> Value {
  let members : Array[ValueMember] = []
  for i = 0; i < elements.length(); i = i + 1 {
    members.push({
      name: "@element$\{i}",
      value: elements[i],
      source: None,
      annotations: [],
    })
  }
  ObjectValue(tag_object_with_class(members, "Dynamic"))
}

///|
fn sort_with_comparator(
  elements : Array[Value],
  comparator : Value,
  context : String,
  bindings : Array[Binding],
  env : Array[ValueBinding],
  class_env : Array[ClassBinding],
  cache : Array[ValueBinding],
  stack : Array[String],
  declarations : Array[Declaration],
  diagnostics : Array[Diagnostic],
  resolve_import : (String) -> EvalResult?,
) -> Array[Value]? {
  let out = elements[:].to_owned()
  for i = 1; i < out.length(); i = i + 1 {
    let cur = out[i]
    let mut j = i - 1
    while j >= 0 {
      let before = match
        apply_function_value(
          "\{context} comparator",
          comparator,
          [cur, out[j]],
          bindings,
          env,
          class_env,
          cache,
          stack,
          declarations,
          diagnostics,
          resolve_import,
        ) {
        Some(BoolValue(b)) => b
        Some(IntValue(n)) => n < 0L
        Some(_) => {
          diagnostics.push(
            diag("\{context} comparator must return Boolean or Int"),
          )
          return None
        }
        None => return None
      }
      if !before {
        break
      }
      out[j + 1] = out[j]
      j = j - 1
    }
    out[j + 1] = cur
  }
  Some(out)
}

///|
/// PKL-151: nanosecond projection of a Duration magnitude+unit pair.
/// Walks the unit ladder so intermediate products stay in Double.
fn duration_to_ns(magnitude : Double, unit : String) -> Double {
  let level = duration_unit_level(unit)
  let mut acc = magnitude
  let mut i = level
  while i > 0 {
    acc = acc * duration_step_factor(i).to_double()
    i = i - 1
  }
  acc
}

///|
/// PKL-151: byte projection of a DataSize magnitude+unit pair.
fn datasize_to_bytes(magnitude : Double, unit : String) -> Double {
  let factor = datasize_byte_factor(unit)
  if factor < 0.0 {
    magnitude
  } else {
    magnitude * factor
  }
}

///|
/// PKL-148bb: a List receiver should keep its `List(...)` constructor
/// shape across method calls that preserve the collection shape
/// (`.map`, `.filter`, `.reverse`, etc.). The shared dispatcher
/// (`eval_listing_method`) emits `ListingValue` uniformly; wrap the
/// returned value to lift it back to `ListValue` for List receivers.
fn eval_list_or_listing_method(
  receiver_is_list : Bool,
  elements : Array[Value],
  method_name : String,
  arguments : Array[Expr],
  bindings : Array[Binding],
  env : Array[ValueBinding],
  class_env : Array[ClassBinding],
  cache : Array[ValueBinding],
  stack : Array[String],
  declarations : Array[Declaration],
  diagnostics : Array[Diagnostic],
  resolve_import : (String) -> EvalResult?,
) -> Value? {
  let result = eval_listing_method(
    elements, method_name, arguments, bindings, env, class_env, cache, stack, declarations,
    diagnostics, resolve_import,
  )
  if receiver_is_list {
    match result {
      Some(ListingValue(xs)) if method_name == "toListing" =>
        Some(ListingValue(xs))
      Some(ListingValue(xs)) => Some(ListValue(xs))
      other => other
    }
  } else {
    result
  }
}

///|
fn eval_listing_method(
  elements : Array[Value],
  method_name : String,
  arguments : Array[Expr],
  bindings : Array[Binding],
  env : Array[ValueBinding],
  class_env : Array[ClassBinding],
  cache : Array[ValueBinding],
  stack : Array[String],
  declarations : Array[Declaration],
  diagnostics : Array[Diagnostic],
  resolve_import : (String) -> EvalResult?,
) -> Value? {
  let arg_values : Array[Value] = []
  let mut ok = true
  for argument in arguments {
    match
      eval_expr_with_bindings(
        argument, bindings, env, class_env, cache, stack, declarations, diagnostics,
        resolve_import,
      ) {
      Some(v) => arg_values.push(v)
      None => ok = false
    }
  }
  if !ok {
    return None
  }
  match method_name {
    "contains" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag(
            "Listing.contains expects 1 argument, got \{arg_values.length()}",
          ),
        )
        return None
      }
      Some(BoolValue(contains_value(elements, arg_values[0])))
    }
    "isDistinctBy" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag(
            "Listing.isDistinctBy expects 1 argument, got \{arg_values.length()}",
          ),
        )
        return None
      }
      let keys : Array[Value] = []
      let mut distinct = true
      for element in elements {
        match
          apply_function_value(
            "Listing.isDistinctBy keyFn",
            arg_values[0],
            [element],
            bindings,
            env,
            class_env,
            cache,
            stack,
            declarations,
            diagnostics,
            resolve_import,
          ) {
          Some(key) =>
            if contains_value(keys, key) {
              distinct = false
              break
            } else {
              keys.push(key)
            }
          None => return None
        }
      }
      Some(BoolValue(distinct))
    }
    // PKL-148: pkl:base Listing.getOrNull(index) — returns the element
    // at `index` or null when out of bounds. Apple Pkl's signature is
    // `(Int) -> T?`.
    "getOrNull" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag(
            "Listing.getOrNull expects 1 argument, got \{arg_values.length()}",
          ),
        )
        return None
      }
      match arg_values[0] {
        IntValue(idx64) => {
          let idx = idx64.to_int()
          if idx64 >= 0L && idx < elements.length() {
            Some(elements[idx])
          } else {
            Some(NullValue)
          }
        }
        _ => {
          diagnostics.push(diag("Listing.getOrNull expects an Int index"))
          None
        }
      }
    }
    "getOrDefault" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag(
            "Listing.getOrDefault expects 1 argument, got \{arg_values.length()}",
          ),
        )
        return None
      }
      match arg_values[0] {
        IntValue(idx64) => {
          let idx = idx64.to_int()
          if idx64 >= 0L && idx < elements.length() {
            Some(elements[idx])
          } else {
            Some(NullValue)
          }
        }
        _ => {
          diagnostics.push(diag("Listing.getOrDefault expects an Int index"))
          None
        }
      }
    }
    // PKL-148: pkl:base Listing.startsWith(other) / endsWith(other) —
    // structural prefix / suffix match against another Listing.
    "startsWith" | "endsWith" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag(
            "Listing.\{method_name} expects 1 argument, got \{arg_values.length()}",
          ),
        )
        return None
      }
      match arg_values[0] {
        ListingValue(other)
        | DefaultedListingValue(_, other, _)
        | ListValue(other)
        | SetValue(other) =>
          if other.length() > elements.length() {
            Some(BoolValue(false))
          } else {
            let offset = if method_name == "startsWith" {
              0
            } else {
              elements.length() - other.length()
            }
            let mut equal = true
            for i = 0; i < other.length(); i = i + 1 {
              if elements[i + offset] != other[i] {
                equal = false
                break
              }
            }
            Some(BoolValue(equal))
          }
        _ => {
          diagnostics.push(
            diag("Listing.\{method_name} expects a Listing argument"),
          )
          None
        }
      }
    }
    "reverse" => {
      if arg_values.length() != 0 {
        diagnostics.push(
          diag(
            "Listing.reverse expects 0 arguments, got \{arg_values.length()}",
          ),
        )
        return None
      }
      let reversed : Array[Value] = []
      let mut i = elements.length() - 1
      while i >= 0 {
        reversed.push(elements[i])
        i = i - 1
      }
      Some(ListingValue(reversed))
    }
    "take" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag("Listing.take expects 1 argument, got \{arg_values.length()}"),
        )
        return None
      }
      match arg_values[0] {
        IntValue(raw) => {
          let raw_i = raw.to_int()
          let n = if raw < 0L {
            0
          } else if raw_i > elements.length() {
            elements.length()
          } else {
            raw_i
          }
          let result : Array[Value] = []
          for i = 0; i < n; i = i + 1 {
            result.push(elements[i])
          }
          Some(ListingValue(result))
        }
        _ => {
          diagnostics.push(diag("Listing.take expects Int argument"))
          None
        }
      }
    }
    "drop" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag("Listing.drop expects 1 argument, got \{arg_values.length()}"),
        )
        return None
      }
      match arg_values[0] {
        IntValue(raw) => {
          let raw_i = raw.to_int()
          let n = if raw < 0L {
            0
          } else if raw_i > elements.length() {
            elements.length()
          } else {
            raw_i
          }
          let result : Array[Value] = []
          for i = n; i < elements.length(); i = i + 1 {
            result.push(elements[i])
          }
          Some(ListingValue(result))
        }
        _ => {
          diagnostics.push(diag("Listing.drop expects Int argument"))
          None
        }
      }
    }
    "join" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag("Listing.join expects 1 argument, got \{arg_values.length()}"),
        )
        return None
      }
      match arg_values[0] {
        StringValue(sep) => {
          let buf = StringBuilder::new()
          for i = 0; i < elements.length(); i = i + 1 {
            if i > 0 {
              buf.write_string(sep)
            }
            match elements[i] {
              ObjectValue(reference) if is_reference_value_members(reference) =>
                match
                  eval_reference_to_string(
                    reference, bindings, env, class_env, cache, stack, declarations,
                    diagnostics, resolve_import,
                  ) {
                  Some(StringValue(text)) => buf.write_string(text)
                  Some(value) =>
                    buf.write_string(value_to_string_for_join(value))
                  None => return None
                }
              value => buf.write_string(value_to_string_for_join(value))
            }
          }
          Some(StringValue(buf.to_string()))
        }
        _ => {
          diagnostics.push(diag("Listing.join expects String separator"))
          None
        }
      }
    }
    "map" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag("Listing.map expects 1 argument, got \{arg_values.length()}"),
        )
        return None
      }
      let result : Array[Value] = []
      for element in elements {
        match
          apply_function_value(
            "Listing.map callback",
            arg_values[0],
            [element],
            bindings,
            env,
            class_env,
            cache,
            stack,
            declarations,
            diagnostics,
            resolve_import,
          ) {
          Some(v) => result.push(v)
          None => return None
        }
      }
      Some(ListingValue(result))
    }
    "filter" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag("Listing.filter expects 1 argument, got \{arg_values.length()}"),
        )
        return None
      }
      let result : Array[Value] = []
      for element in elements {
        match
          apply_function_value(
            "Listing.filter predicate",
            arg_values[0],
            [element],
            bindings,
            env,
            class_env,
            cache,
            stack,
            declarations,
            diagnostics,
            resolve_import,
          ) {
          Some(BoolValue(true)) => result.push(element)
          Some(BoolValue(false)) => ()
          Some(value) => {
            diagnostics.push(diag(pkl_bool_return_type_message(value)))
            return None
          }
          None => return None
        }
      }
      Some(ListingValue(result))
    }
    "fold" => {
      if arg_values.length() != 2 {
        diagnostics.push(
          diag("Listing.fold expects 2 arguments, got \{arg_values.length()}"),
        )
        return None
      }
      let mut acc = arg_values[0]
      let callback = arg_values[1]
      for element in elements {
        match
          apply_function_value(
            "Listing.fold combine",
            callback,
            [acc, element],
            bindings,
            env,
            class_env,
            cache,
            stack,
            declarations,
            diagnostics,
            resolve_import,
          ) {
          Some(v) => acc = v
          None => return None
        }
      }
      Some(acc)
    }
    // PKL-148h: `.toList()` on a Listing returns a `ListValue` so the
    // renderer projects through the `List(...)` constructor form. The
    // arity guard is preserved from the PKL-134 implementation. `.toMap`
    // on a Listing without Pair entries is the empty map — matches
    // Apple Pkl's behaviour when the Listing is not a Listing-of-Pair.
    "toList" => {
      if arg_values.length() != 0 {
        diagnostics.push(
          diag("Listing.toList expects 0 arguments, got \{arg_values.length()}"),
        )
        return None
      }
      match first_deferred_error_message(ListingValue(elements)) {
        Some(message) => {
          diagnostics.push(diag(message))
          return None
        }
        None => ()
      }
      Some(ListValue(elements))
    }
    "toBytes" => {
      if arg_values.length() != 0 {
        diagnostics.push(
          diag(
            "Listing.toBytes expects 0 arguments, got \{arg_values.length()}",
          ),
        )
        return None
      }
      build_bytes_from_int_listing(elements, diagnostics)
    }
    "toMap" =>
      if arg_values.length() == 0 {
        Some(MappingValue([]))
      } else if arg_values.length() == 2 {
        let entries : Array[ValueEntry] = []
        for element in elements {
          let key = match
            apply_function_value(
              "Listing.toMap keyFn",
              arg_values[0],
              [element],
              bindings,
              env,
              class_env,
              cache,
              stack,
              declarations,
              diagnostics,
              resolve_import,
            ) {
            Some(v) => v
            None => return None
          }
          let value = match
            apply_function_value(
              "Listing.toMap valueFn",
              arg_values[1],
              [element],
              bindings,
              env,
              class_env,
              cache,
              stack,
              declarations,
              diagnostics,
              resolve_import,
            ) {
            Some(v) => v
            None => return None
          }
          entries.push({ key, value })
        }
        Some(MapValue(entries))
      } else {
        diagnostics.push(
          diag(
            "Listing.toMap expects 0 or 2 arguments, got \{arg_values.length()}",
          ),
        )
        None
      }
    // PKL-135: flatMap concatenates the listing results of each element's
    // transform call. Upstream allows Collection (List | Listing | Set);
    // pkl-mbt collapses those into ListingValue, so the shape stays consistent.
    "flatMap" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag("Listing.flatMap expects 1 argument, got \{arg_values.length()}"),
        )
        return None
      }
      let result : Array[Value] = []
      for element in elements {
        match
          apply_function_value(
            "Listing.flatMap callback",
            arg_values[0],
            [element],
            bindings,
            env,
            class_env,
            cache,
            stack,
            declarations,
            diagnostics,
            resolve_import,
          ) {
          Some(ListingValue(inner))
          | Some(DefaultedListingValue(_, inner, _))
          | Some(ListValue(inner))
          | Some(SetValue(inner)) =>
            for v in inner {
              result.push(v)
            }
          Some(value) => {
            diagnostics.push(diag(pkl_collection_return_type_message(value)))
            return None
          }
          None => return None
        }
      }
      Some(ListingValue(result))
    }
    "count" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag("Listing.count expects 1 argument, got \{arg_values.length()}"),
        )
        return None
      }
      let mut n = 0
      for element in elements {
        match
          apply_function_value(
            "Listing.count predicate",
            arg_values[0],
            [element],
            bindings,
            env,
            class_env,
            cache,
            stack,
            declarations,
            diagnostics,
            resolve_import,
          ) {
          Some(BoolValue(true)) => n = n + 1
          Some(BoolValue(false)) => ()
          Some(value) => {
            diagnostics.push(diag(pkl_bool_return_type_message(value)))
            return None
          }
          None => return None
        }
      }
      Some(IntValue(n.to_int64()))
    }
    "every" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag("Listing.every expects 1 argument, got \{arg_values.length()}"),
        )
        return None
      }
      for element in elements {
        match
          apply_function_value(
            "Listing.every predicate",
            arg_values[0],
            [element],
            bindings,
            env,
            class_env,
            cache,
            stack,
            declarations,
            diagnostics,
            resolve_import,
          ) {
          Some(BoolValue(true)) => ()
          Some(BoolValue(false)) => return Some(BoolValue(false))
          Some(value) => {
            diagnostics.push(diag(pkl_bool_return_type_message(value)))
            return None
          }
          None => return None
        }
      }
      Some(BoolValue(true))
    }
    "any" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag("Listing.any expects 1 argument, got \{arg_values.length()}"),
        )
        return None
      }
      for element in elements {
        match
          apply_function_value(
            "Listing.any predicate",
            arg_values[0],
            [element],
            bindings,
            env,
            class_env,
            cache,
            stack,
            declarations,
            diagnostics,
            resolve_import,
          ) {
          Some(BoolValue(true)) => return Some(BoolValue(true))
          Some(BoolValue(false)) => ()
          Some(value) => {
            diagnostics.push(diag(pkl_bool_return_type_message(value)))
            return None
          }
          None => return None
        }
      }
      Some(BoolValue(false))
    }
    "none" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag("Listing.none expects 1 argument, got \{arg_values.length()}"),
        )
        return None
      }
      for element in elements {
        match
          apply_function_value(
            "Listing.none predicate",
            arg_values[0],
            [element],
            bindings,
            env,
            class_env,
            cache,
            stack,
            declarations,
            diagnostics,
            resolve_import,
          ) {
          Some(BoolValue(true)) => return Some(BoolValue(false))
          Some(BoolValue(false)) => ()
          Some(value) => {
            diagnostics.push(diag(pkl_bool_return_type_message(value)))
            return None
          }
          None => return None
        }
      }
      Some(BoolValue(true))
    }
    "find" | "findOrNull" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag(
            "Listing.\{method_name} expects 1 argument, got \{arg_values.length()}",
          ),
        )
        return None
      }
      for element in elements {
        match
          apply_function_value(
            "Listing.\{method_name} predicate",
            arg_values[0],
            [element],
            bindings,
            env,
            class_env,
            cache,
            stack,
            declarations,
            diagnostics,
            resolve_import,
          ) {
          Some(BoolValue(true)) => return Some(element)
          Some(BoolValue(false)) => ()
          Some(value) => {
            diagnostics.push(diag(pkl_bool_return_type_message(value)))
            return None
          }
          None => return None
        }
      }
      // Apple Pkl: `find` throws when no match, `findOrNull` returns null.
      if method_name == "findOrNull" {
        Some(NullValue)
      } else {
        diagnostics.push(diag("Listing.find did not match any element"))
        None
      }
    }
    "findLast" | "findLastOrNull" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag(
            "Listing.\{method_name} expects 1 argument, got \{arg_values.length()}",
          ),
        )
        return None
      }
      let mut i = elements.length() - 1
      while i >= 0 {
        let element = elements[i]
        match
          apply_function_value(
            "Listing.\{method_name} predicate",
            arg_values[0],
            [element],
            bindings,
            env,
            class_env,
            cache,
            stack,
            declarations,
            diagnostics,
            resolve_import,
          ) {
          Some(BoolValue(true)) => return Some(element)
          Some(BoolValue(false)) => ()
          Some(value) => {
            diagnostics.push(diag(pkl_bool_return_type_message(value)))
            return None
          }
          None => return None
        }
        i = i - 1
      }
      if method_name == "findLastOrNull" {
        Some(NullValue)
      } else {
        diagnostics.push(diag("Listing.findLast did not match any element"))
        None
      }
    }
    // PKL-151: indexOf(elem) / lastIndexOf(elem) — return position of
    // a structurally-equal element; raise on miss.
    "indexOf" | "lastIndexOf" | "indexOfOrNull" | "lastIndexOfOrNull" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag(
            "Listing.\{method_name} expects 1 argument, got \{arg_values.length()}",
          ),
        )
        return None
      }
      let needle = arg_values[0]
      let mut found = -1
      if method_name == "indexOf" || method_name == "indexOfOrNull" {
        for i = 0; i < elements.length(); i = i + 1 {
          if elements[i] == needle {
            found = i
            break
          }
        }
      } else {
        let mut i = elements.length() - 1
        while i >= 0 {
          if elements[i] == needle {
            found = i
            break
          }
          i = i - 1
        }
      }
      if found < 0 {
        if method_name == "indexOfOrNull" || method_name == "lastIndexOfOrNull" {
          return Some(NullValue)
        }
        diagnostics.push(diag("Element not found in Listing."))
        None
      } else {
        Some(IntValue(found.to_int64()))
      }
    }
    // PKL-151: findIndex(pred) / findLastIndex(pred) — predicate
    // sibling of indexOf; raises on no match.
    "findIndex" | "findLastIndex" | "findIndexOrNull" | "findLastIndexOrNull" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag(
            "Listing.\{method_name} expects 1 argument, got \{arg_values.length()}",
          ),
        )
        return None
      }
      let pred = arg_values[0]
      let walk_forward = method_name == "findIndex" ||
        method_name == "findIndexOrNull"
      let mut found = -1
      let range = if walk_forward {
        let r : Array[Int] = []
        for i = 0; i < elements.length(); i = i + 1 {
          r.push(i)
        }
        r
      } else {
        let r : Array[Int] = []
        let mut i = elements.length() - 1
        while i >= 0 {
          r.push(i)
          i = i - 1
        }
        r
      }
      for i in range {
        match
          apply_function_value(
            "Listing.\{method_name} pred",
            pred,
            [elements[i]],
            bindings,
            env,
            class_env,
            cache,
            stack,
            declarations,
            diagnostics,
            resolve_import,
          ) {
          Some(BoolValue(true)) => {
            found = i
            break
          }
          Some(BoolValue(false)) => continue
          Some(value) => {
            diagnostics.push(diag(pkl_bool_return_type_message(value)))
            return None
          }
          None => return None
        }
      }
      if found < 0 {
        if method_name == "findIndexOrNull" ||
          method_name == "findLastIndexOrNull" {
          return Some(NullValue)
        }
        diagnostics.push(
          diag("Listing.\{method_name} did not match any element"),
        )
        None
      } else {
        Some(IntValue(found.to_int64()))
      }
    }
    // PKL-151: sortBy / minBy / maxBy / distinctBy — extract a key,
    // then compare on the key (Pkl ordering for Int / Float / String /
    // Duration / DataSize).
    "sortBy" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag("Listing.sortBy expects 1 argument, got \{arg_values.length()}"),
        )
        return None
      }
      let key_fn = arg_values[0]
      let keys : Array[Value] = []
      for e in elements {
        match
          apply_function_value(
            "Listing.sortBy keyFn",
            key_fn,
            [e],
            bindings,
            env,
            class_env,
            cache,
            stack,
            declarations,
            diagnostics,
            resolve_import,
          ) {
          Some(v) => keys.push(v)
          None => return None
        }
      }
      let indexed : Array[(Int, Value)] = []
      for i = 0; i < elements.length(); i = i + 1 {
        indexed.push((i, keys[i]))
      }
      // Simple insertion sort — Listings in practice stay small.
      for i = 1; i < indexed.length(); i = i + 1 {
        let cur = indexed[i]
        let mut j = i - 1
        while j >= 0 {
          let cmp = compare_values(indexed[j].1, cur.1)
          if cmp == incomparable_value_ordering_sentinel() {
            diagnostics.push(
              diag(
                undefined_operator_for_operand_types_message(
                  GreaterThan,
                  indexed[j].1,
                  cur.1,
                ),
              ),
            )
            return None
          }
          if cmp <= 0 {
            break
          }
          indexed[j + 1] = indexed[j]
          j = j - 1
        }
        indexed[j + 1] = cur
      }
      let out : Array[Value] = []
      for pair in indexed {
        out.push(elements[pair.0])
      }
      Some(ListingValue(out))
    }
    "sortWith" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag(
            "Listing.sortWith expects 1 argument, got \{arg_values.length()}",
          ),
        )
        return None
      }
      match
        sort_with_comparator(
          elements,
          arg_values[0],
          "Listing.sortWith",
          bindings,
          env,
          class_env,
          cache,
          stack,
          declarations,
          diagnostics,
          resolve_import,
        ) {
        Some(out) => Some(ListingValue(out))
        None => None
      }
    }
    "minWith" | "maxWith" | "minWithOrNull" | "maxWithOrNull" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag(
            "Listing.\{method_name} expects 1 argument, got \{arg_values.length()}",
          ),
        )
        return None
      }
      if elements.length() == 0 {
        if method_name == "minWithOrNull" || method_name == "maxWithOrNull" {
          return Some(NullValue)
        }
        diagnostics.push(diag(collection_non_empty_message(elements)))
        return None
      }
      match
        sort_with_comparator(
          elements,
          arg_values[0],
          "Listing.\{method_name}",
          bindings,
          env,
          class_env,
          cache,
          stack,
          declarations,
          diagnostics,
          resolve_import,
        ) {
        Some(out) =>
          if method_name == "maxWith" || method_name == "maxWithOrNull" {
            Some(out[out.length() - 1])
          } else {
            Some(out[0])
          }
        None => None
      }
    }
    "minBy" | "maxBy" | "minByOrNull" | "maxByOrNull" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag(
            "Listing.\{method_name} expects 1 argument, got \{arg_values.length()}",
          ),
        )
        return None
      }
      if elements.length() == 0 {
        if method_name == "minByOrNull" || method_name == "maxByOrNull" {
          return Some(NullValue)
        }
        diagnostics.push(diag(collection_non_empty_message(elements)))
        return None
      }
      let key_fn = arg_values[0]
      let pick_max = method_name == "maxBy" || method_name == "maxByOrNull"
      let mut best_idx = 0
      let mut best_key = match
        apply_function_value(
          "Listing.\{method_name} keyFn",
          key_fn,
          [elements[0]],
          bindings,
          env,
          class_env,
          cache,
          stack,
          declarations,
          diagnostics,
          resolve_import,
        ) {
        Some(v) => v
        None => return None
      }
      for i = 1; i < elements.length(); i = i + 1 {
        let k = match
          apply_function_value(
            "Listing.\{method_name} keyFn",
            key_fn,
            [elements[i]],
            bindings,
            env,
            class_env,
            cache,
            stack,
            declarations,
            diagnostics,
            resolve_import,
          ) {
          Some(v) => v
          None => return None
        }
        let cmp = compare_values(k, best_key)
        if cmp == incomparable_value_ordering_sentinel() {
          let op = if pick_max { GreaterThan } else { LessThan }
          diagnostics.push(
            diag(undefined_operator_for_operand_types_message(op, k, best_key)),
          )
          return None
        }
        if pick_max {
          if cmp > 0 {
            best_idx = i
            best_key = k
          }
        } else if cmp < 0 {
          best_idx = i
          best_key = k
        }
      }
      Some(elements[best_idx])
    }
    "distinctBy" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag(
            "Listing.distinctBy expects 1 argument, got \{arg_values.length()}",
          ),
        )
        return None
      }
      let key_fn = arg_values[0]
      let keys : Array[Value] = []
      let out : Array[Value] = []
      for e in elements {
        let k = match
          apply_function_value(
            "Listing.distinctBy keyFn",
            key_fn,
            [e],
            bindings,
            env,
            class_env,
            cache,
            stack,
            declarations,
            diagnostics,
            resolve_import,
          ) {
          Some(v) => v
          None => return None
        }
        if !contains_value(keys, k) {
          keys.push(k)
          out.push(e)
        }
      }
      Some(ListingValue(out))
    }
    // PKL-151: sort() — zero-arg ascending sort using `compare_values`.
    "sort" => {
      if arg_values.length() != 0 {
        diagnostics.push(
          diag("Listing.sort expects 0 arguments, got \{arg_values.length()}"),
        )
        return None
      }
      let out = elements[:].to_owned()
      for i = 1; i < out.length(); i = i + 1 {
        let cur = out[i]
        let mut j = i - 1
        while j >= 0 {
          let cmp = compare_values(out[j], cur)
          if cmp == incomparable_value_ordering_sentinel() {
            diagnostics.push(
              diag(
                undefined_operator_for_operand_types_message(
                  LessThan,
                  cur,
                  out[j],
                ),
              ),
            )
            return None
          }
          if cmp <= 0 {
            break
          }
          out[j + 1] = out[j]
          j = j - 1
        }
        out[j + 1] = cur
      }
      Some(ListingValue(out))
    }
    // PKL-151: takeWhile / dropWhile and their `*Last*` variants —
    // walk from the start (or end) while the predicate holds.
    "takeWhile" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag(
            "Listing.takeWhile expects 1 argument, got \{arg_values.length()}",
          ),
        )
        return None
      }
      let pred = arg_values[0]
      let out : Array[Value] = []
      for e in elements {
        match
          apply_function_value(
            "Listing.takeWhile pred",
            pred,
            [e],
            bindings,
            env,
            class_env,
            cache,
            stack,
            declarations,
            diagnostics,
            resolve_import,
          ) {
          Some(BoolValue(true)) => out.push(e)
          Some(BoolValue(false)) => break
          Some(value) => {
            diagnostics.push(diag(pkl_bool_return_type_message(value)))
            return None
          }
          None => return None
        }
      }
      Some(ListingValue(out))
    }
    "dropWhile" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag(
            "Listing.dropWhile expects 1 argument, got \{arg_values.length()}",
          ),
        )
        return None
      }
      let pred = arg_values[0]
      let out : Array[Value] = []
      let mut dropping = true
      for e in elements {
        if dropping {
          match
            apply_function_value(
              "Listing.dropWhile pred",
              pred,
              [e],
              bindings,
              env,
              class_env,
              cache,
              stack,
              declarations,
              diagnostics,
              resolve_import,
            ) {
            Some(BoolValue(true)) => continue
            Some(BoolValue(false)) => {
              dropping = false
              out.push(e)
            }
            Some(value) => {
              diagnostics.push(diag(pkl_bool_return_type_message(value)))
              return None
            }
            None => return None
          }
        } else {
          out.push(e)
        }
      }
      Some(ListingValue(out))
    }
    "takeLast" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag(
            "Listing.takeLast expects 1 argument, got \{arg_values.length()}",
          ),
        )
        return None
      }
      match arg_values[0] {
        IntValue(raw) => {
          let raw_i = raw.to_int()
          let n = if raw < 0L {
            0
          } else if raw_i > elements.length() {
            elements.length()
          } else {
            raw_i
          }
          let out : Array[Value] = []
          for i = elements.length() - n; i < elements.length(); i = i + 1 {
            out.push(elements[i])
          }
          Some(ListingValue(out))
        }
        _ => {
          diagnostics.push(diag("Listing.takeLast expects Int argument"))
          None
        }
      }
    }
    "dropLast" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag(
            "Listing.dropLast expects 1 argument, got \{arg_values.length()}",
          ),
        )
        return None
      }
      match arg_values[0] {
        IntValue(raw) => {
          let raw_i = raw.to_int()
          let n = if raw < 0L {
            0
          } else if raw_i > elements.length() {
            elements.length()
          } else {
            raw_i
          }
          let out : Array[Value] = []
          for i = 0; i < elements.length() - n; i = i + 1 {
            out.push(elements[i])
          }
          Some(ListingValue(out))
        }
        _ => {
          diagnostics.push(diag("Listing.dropLast expects Int argument"))
          None
        }
      }
    }
    // PKL-151: repeat(n) — concat self `n` times. Negative `n` raises.
    "repeat" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag("Listing.repeat expects 1 argument, got \{arg_values.length()}"),
        )
        return None
      }
      match arg_values[0] {
        IntValue(n) =>
          if n < 0L {
            diagnostics.push(
              diag("Expected a positive number, but got `\{n}`."),
            )
            None
          } else {
            let out : Array[Value] = []
            for _ in 0.. {
          diagnostics.push(diag("Listing.repeat expects Int argument"))
          None
        }
      }
    }
    // PKL-151: add(elem) / replace(idx, elem) — non-mutating returns.
    "add" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag("Listing.add expects 1 argument, got \{arg_values.length()}"),
        )
        return None
      }
      let out = elements[:].to_owned()
      out.push(arg_values[0])
      Some(ListingValue(out))
    }
    "replace" => {
      if arg_values.length() != 2 {
        diagnostics.push(
          diag(
            "Listing.replace expects 2 arguments, got \{arg_values.length()}",
          ),
        )
        return None
      }
      match arg_values[0] {
        IntValue(i64) => {
          let i = i64.to_int()
          if i64 < 0L || i >= elements.length() {
            diagnostics.push(
              diag(
                collection_index_range_message(
                  i64,
                  0,
                  elements.length() - 1,
                  elements,
                ),
              ),
            )
            None
          } else {
            let out = elements[:].to_owned()
            out[i] = arg_values[1]
            Some(ListingValue(out))
          }
        }
        _ => {
          diagnostics.push(diag("Listing.replace expects (Int, T) arguments"))
          None
        }
      }
    }
    // PKL-151: mapNonNull(fn) — map then strip nulls.
    "mapNonNull" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag(
            "Listing.mapNonNull expects 1 argument, got \{arg_values.length()}",
          ),
        )
        return None
      }
      let fn_v = arg_values[0]
      let out : Array[Value] = []
      for e in elements {
        match
          apply_function_value(
            "Listing.mapNonNull fn",
            fn_v,
            [e],
            bindings,
            env,
            class_env,
            cache,
            stack,
            declarations,
            diagnostics,
            resolve_import,
          ) {
          Some(NullValue) => continue
          Some(v) => out.push(v)
          None => return None
        }
      }
      Some(ListingValue(out))
    }
    "takeLastWhile" | "dropLastWhile" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag(
            "Listing.\{method_name} expects 1 argument, got \{arg_values.length()}",
          ),
        )
        return None
      }
      let pred = arg_values[0]
      let mut cut = elements.length()
      let mut i = elements.length() - 1
      while i >= 0 {
        match
          apply_function_value(
            "Listing.\{method_name} pred",
            pred,
            [elements[i]],
            bindings,
            env,
            class_env,
            cache,
            stack,
            declarations,
            diagnostics,
            resolve_import,
          ) {
          Some(BoolValue(true)) => {
            cut = i
            i = i - 1
          }
          Some(BoolValue(false)) => break
          Some(value) => {
            diagnostics.push(diag(pkl_bool_return_type_message(value)))
            return None
          }
          None => return None
        }
      }
      if method_name == "takeLastWhile" {
        Some(ListingValue(list_slice(elements, cut, elements.length())))
      } else {
        Some(ListingValue(list_slice(elements, 0, cut)))
      }
    }
    "foldBack" => {
      if arg_values.length() != 2 {
        diagnostics.push(
          diag(
            "Listing.foldBack expects 2 arguments, got \{arg_values.length()}",
          ),
        )
        return None
      }
      let callback = arg_values[1]
      let mut acc = arg_values[0]
      let mut i = elements.length() - 1
      while i >= 0 {
        match
          apply_function_value(
            "Listing.foldBack combine",
            callback,
            [elements[i], acc],
            bindings,
            env,
            class_env,
            cache,
            stack,
            declarations,
            diagnostics,
            resolve_import,
          ) {
          Some(v) => acc = v
          None => return None
        }
        i = i - 1
      }
      Some(acc)
    }
    "reduce" | "reduceOrNull" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag(
            "Listing.\{method_name} expects 1 argument, got \{arg_values.length()}",
          ),
        )
        return None
      }
      if elements.length() == 0 {
        if method_name == "reduceOrNull" {
          return Some(NullValue)
        }
        diagnostics.push(diag(collection_non_empty_message(elements)))
        return None
      }
      let callback = arg_values[0]
      let mut acc = elements[0]
      for i = 1; i < elements.length(); i = i + 1 {
        match
          apply_function_value(
            "Listing.\{method_name} combine",
            callback,
            [acc, elements[i]],
            bindings,
            env,
            class_env,
            cache,
            stack,
            declarations,
            diagnostics,
            resolve_import,
          ) {
          Some(v) => acc = v
          None => return None
        }
      }
      Some(acc)
    }
    "groupBy" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag("Listing.groupBy expects 1 argument, got \{arg_values.length()}"),
        )
        return None
      }
      let entries : Array[ValueEntry] = []
      for element in elements {
        let key = match
          apply_function_value(
            "Listing.groupBy keyFn",
            arg_values[0],
            [element],
            bindings,
            env,
            class_env,
            cache,
            stack,
            declarations,
            diagnostics,
            resolve_import,
          ) {
          Some(v) => v
          None => return None
        }
        let mut found = false
        for i = 0; i < entries.length(); i = i + 1 {
          if values_equal(entries[i].key, key) {
            match entries[i].value {
              ListValue(xs) => {
                let grouped : Array[Value] = xs[:].to_owned()
                grouped.push(element)
                entries[i] = { key: entries[i].key, value: ListValue(grouped) }
              }
              _ => ()
            }
            found = true
            break
          }
        }
        if !found {
          entries.push({ key, value: ListValue([element]) })
        }
      }
      Some(MapValue(entries))
    }
    "replaceRange" | "replaceRangeOrNull" => {
      if arg_values.length() != 3 {
        diagnostics.push(
          diag(
            "Listing.\{method_name} expects 3 arguments, got \{arg_values.length()}",
          ),
        )
        return None
      }
      match (arg_values[0], arg_values[1], arg_values[2]) {
        (IntValue(start64), IntValue(end64), ListValue(replacement))
        | (IntValue(start64), IntValue(end64), ListingValue(replacement))
        | (IntValue(start64), IntValue(end64), SetValue(replacement)) => {
          let start = start64.to_int()
          let end = end64.to_int()
          if start64 < 0L {
            if method_name == "replaceRangeOrNull" {
              return Some(NullValue)
            }
            diagnostics.push(
              diag(
                collection_index_range_message(
                  start64,
                  0,
                  elements.length(),
                  elements,
                ),
              ),
            )
            return None
          }
          if end64 > elements.length().to_int64() || start > end {
            if method_name == "replaceRangeOrNull" {
              return Some(NullValue)
            }
            diagnostics.push(
              diag(
                collection_index_range_message(
                  end64,
                  start,
                  elements.length(),
                  elements,
                ),
              ),
            )
            return None
          }
          let out : Array[Value] = []
          for i = 0; i < start; i = i + 1 {
            out.push(elements[i])
          }
          for v in replacement {
            out.push(v)
          }
          for i = end; i < elements.length(); i = i + 1 {
            out.push(elements[i])
          }
          Some(ListingValue(out))
        }
        _ => {
          diagnostics.push(
            diag(
              "Listing.\{method_name} expects (Int, Int, Collection) arguments",
            ),
          )
          None
        }
      }
    }
    "replaceOrNull" => {
      if arg_values.length() != 2 {
        diagnostics.push(
          diag(
            "Listing.replaceOrNull expects 2 arguments, got \{arg_values.length()}",
          ),
        )
        return None
      }
      match arg_values[0] {
        IntValue(i64) => {
          let i = i64.to_int()
          if i64 < 0L || i >= elements.length() {
            Some(NullValue)
          } else {
            let out = elements[:].to_owned()
            out[i] = arg_values[1]
            Some(ListingValue(out))
          }
        }
        _ => {
          diagnostics.push(
            diag("Listing.replaceOrNull expects (Int, T) arguments"),
          )
          None
        }
      }
    }
    "sublistOrNull" => {
      if arg_values.length() != 2 {
        diagnostics.push(
          diag(
            "Listing.sublistOrNull expects 2 arguments, got \{arg_values.length()}",
          ),
        )
        return None
      }
      match (arg_values[0], arg_values[1]) {
        (IntValue(start64), IntValue(end64)) => {
          let start = start64.to_int()
          let end = end64.to_int()
          if start64 < 0L || end64 > elements.length().to_int64() || start > end {
            Some(NullValue)
          } else {
            Some(ListingValue(list_slice(elements, start, end)))
          }
        }
        _ => {
          diagnostics.push(
            diag("Listing.sublistOrNull expects (Int, Int) arguments"),
          )
          None
        }
      }
    }
    "split" | "splitOrNull" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag(
            "Listing.\{method_name} expects 1 argument, got \{arg_values.length()}",
          ),
        )
        return None
      }
      match arg_values[0] {
        IntValue(index64) => {
          let index = index64.to_int()
          if index64 < 0L || index > elements.length() {
            if method_name == "splitOrNull" {
              return Some(NullValue)
            }
            diagnostics.push(
              diag(
                collection_index_range_message(
                  index64,
                  0,
                  elements.length(),
                  elements,
                ),
              ),
            )
            return None
          }
          Some(
            PairValue(
              ListValue(list_slice(elements, 0, index)),
              ListValue(list_slice(elements, index, elements.length())),
            ),
          )
        }
        _ => {
          diagnostics.push(diag("Listing.\{method_name} expects Int argument"))
          None
        }
      }
    }
    "partition" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag(
            "Listing.partition expects 1 argument, got \{arg_values.length()}",
          ),
        )
        return None
      }
      let yes : Array[Value] = []
      let no : Array[Value] = []
      for element in elements {
        match
          apply_function_value(
            "Listing.partition predicate",
            arg_values[0],
            [element],
            bindings,
            env,
            class_env,
            cache,
            stack,
            declarations,
            diagnostics,
            resolve_import,
          ) {
          Some(BoolValue(true)) => yes.push(element)
          Some(BoolValue(false)) => no.push(element)
          Some(value) => {
            diagnostics.push(diag(pkl_bool_return_type_message(value)))
            return None
          }
          None => return None
        }
      }
      Some(PairValue(ListValue(yes), ListValue(no)))
    }
    "zip" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag("Listing.zip expects 1 argument, got \{arg_values.length()}"),
        )
        return None
      }
      let other = match arg_values[0] {
        ListValue(xs) | ListingValue(xs) | SetValue(xs) => xs
        _ => {
          diagnostics.push(diag("Listing.zip expects a Collection argument"))
          return None
        }
      }
      let out : Array[Value] = []
      let n = if elements.length() < other.length() {
        elements.length()
      } else {
        other.length()
      }
      for i = 0; i < n; i = i + 1 {
        out.push(PairValue(elements[i], other[i]))
      }
      Some(ListingValue(out))
    }
    "filterIndexed" | "mapIndexed" | "flatMapIndexed" | "mapNonNullIndexed" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag(
            "Listing.\{method_name} expects 1 argument, got \{arg_values.length()}",
          ),
        )
        return None
      }
      let out : Array[Value] = []
      for i = 0; i < elements.length(); i = i + 1 {
        match
          apply_function_value(
            "Listing.\{method_name} callback",
            arg_values[0],
            [IntValue(i.to_int64()), elements[i]],
            bindings,
            env,
            class_env,
            cache,
            stack,
            declarations,
            diagnostics,
            resolve_import,
          ) {
          Some(value) =>
            if method_name == "filterIndexed" {
              match value {
                BoolValue(true) => out.push(elements[i])
                BoolValue(false) => ()
                _ => {
                  diagnostics.push(diag(pkl_bool_return_type_message(value)))
                  return None
                }
              }
            } else if method_name == "flatMapIndexed" {
              match value {
                ListValue(xs) | ListingValue(xs) | SetValue(xs) =>
                  for v in xs {
                    out.push(v)
                  }
                _ => {
                  diagnostics.push(
                    diag(pkl_collection_return_type_message(value)),
                  )
                  return None
                }
              }
            } else if method_name == "mapNonNullIndexed" {
              if value != NullValue {
                out.push(value)
              }
            } else {
              out.push(value)
            }
          None => return None
        }
      }
      Some(ListingValue(out))
    }
    "foldIndexed" => {
      if arg_values.length() != 2 {
        diagnostics.push(
          diag(
            "Listing.foldIndexed expects 2 arguments, got \{arg_values.length()}",
          ),
        )
        return None
      }
      let mut acc = arg_values[0]
      let callback = arg_values[1]
      for i = 0; i < elements.length(); i = i + 1 {
        match
          apply_function_value(
            "Listing.foldIndexed combine",
            callback,
            [IntValue(i.to_int64()), acc, elements[i]],
            bindings,
            env,
            class_env,
            cache,
            stack,
            declarations,
            diagnostics,
            resolve_import,
          ) {
          Some(v) => acc = v
          None => return None
        }
      }
      Some(acc)
    }
    "filterIsInstance" => {
      if arg_values.length() != 1 {
        diagnostics.push(
          diag(
            "Listing.filterIsInstance expects 1 argument, got \{arg_values.length()}",
          ),
        )
        return None
      }
      let target = class_mirror_simple_name(arg_values[0])
      let out : Array[Value] = []
      for element in elements {
        let keep = match target {
          Some("Any") => true
          Some("Number") => element is IntValue(_) || element is FloatValue(_)
          Some("Int") => element is IntValue(_)
          Some("Float") => element is FloatValue(_)
          Some("String") => element is StringValue(_)
          Some("Boolean") => element is BoolValue(_)
          Some("List") => element is ListValue(_)
          Some("Listing") =>
            element is ListingValue(_) ||
            element is DefaultedListingValue(_, _, _)
          Some("Set") => element is SetValue(_)
          _ => false
        }
        if keep {
          out.push(element)
        }
      }
      Some(ListingValue(out))
    }
    "toDynamic" => {
      if arg_values.length() != 0 {
        diagnostics.push(
          diag(
            "Listing.toDynamic expects 0 arguments, got \{arg_values.length()}",
          ),
        )
        return None
      }
      Some(dynamic_from_elements(elements))
    }
    // Apple Pkl allows zero-arg property reads (e.g. `list.toSet`) to be
    // written as method calls (`list.toSet()`). Delegate the no-arg
    // surface back to the property evaluator so both forms agree.
    "toSet"
    | "toListing"
    | "first"
    | "last"
    | "firstOrNull"
    | "lastOrNull"
    | "distinct"
    | "isEmpty"
    | "isNotEmpty"
    | "isDistinct"
    | "single"
    | "rest"
    | "lastIndex"
    | "min"
    | "max"
    | "flatten"
    | "filterNonNull" =>
      if arg_values.length() != 0 {
        diagnostics.push(
          diag(
            "Listing.\{method_name} expects 0 arguments, got \{arg_values.length()}",
          ),
        )
        None
      } else {
        eval_listing_property(elements, method_name, diagnostics)
      }
    _ => None
  }
}