Skip to content

bug(analyzer): infering and binding template parametersΒ #621

@norberttech

Description

@norberttech

🐞 Describe the Bug

I think mago should infer template type parameters from actual function arguments.

When calling a generic function with a concrete type argument (e.g., Type<array<string, string>>), mago does not bind the template parameters and instead reports a type mismatch.

Expected behavior:
Mago should infer that TKey = string and TValue = string from the Type<array<string, string>> argument and validate the types match (which they do).

Actual behavior:
Mago leaves template parameters unbound and reports a type error.

πŸ”„ Steps to Reproduce

  1. Checkout branch from 1892 replace php cs fixer and rector with mago linter formatterΒ flow-php/flow#1894
  2. Run ./tools/mago/vendor/bin/mago analyze --reporting-format=short --minimum-report-level=error

βš™οΈ Configuration (mago.toml)

php-version = "8.2.0"

[source]
paths = [
    "src/adapter/etl-adapter-avro/src/Flow",
    "src/adapter/etl-adapter-avro/tests/Flow",
    "src/adapter/etl-adapter-chartjs/src/Flow",
    "src/adapter/etl-adapter-chartjs/tests/Flow",
    "src/adapter/etl-adapter-csv/src/Flow",
    "src/adapter/etl-adapter-csv/tests/Flow",
    "src/adapter/etl-adapter-doctrine/src/Flow",
    "src/adapter/etl-adapter-doctrine/tests/Flow",
    "src/adapter/etl-adapter-elasticsearch/src/Flow",
    "src/adapter/etl-adapter-elasticsearch/tests/Flow",
    "src/adapter/etl-adapter-excel/src/Flow",
    "src/adapter/etl-adapter-excel/tests/Flow",
    "src/adapter/etl-adapter-google-sheet/src/Flow",
    "src/adapter/etl-adapter-google-sheet/tests/Flow",
    "src/adapter/etl-adapter-http/src/Flow",
    "src/adapter/etl-adapter-http/tests/Flow",
    "src/adapter/etl-adapter-json/src/Flow",
    "src/adapter/etl-adapter-json/tests/Flow",
    "src/adapter/etl-adapter-logger/src/Flow",
    "src/adapter/etl-adapter-logger/tests/Flow",
    "src/adapter/etl-adapter-meilisearch/src/Flow",
    "src/adapter/etl-adapter-meilisearch/tests/Flow",
    "src/adapter/etl-adapter-parquet/src/Flow",
    "src/adapter/etl-adapter-parquet/tests/Flow",
    "src/adapter/etl-adapter-text/src/Flow",
    "src/adapter/etl-adapter-text/tests/Flow",
    "src/adapter/etl-adapter-xml/src/Flow",
    "src/adapter/etl-adapter-xml/tests/Flow",
    "src/bridge/filesystem/async-aws/src/Flow",
    "src/bridge/filesystem/async-aws/tests/Flow",
    "src/bridge/filesystem/azure/src/Flow",
    "src/bridge/filesystem/azure/tests/Flow",
    "src/bridge/monolog/http/src/Flow",
    "src/bridge/monolog/http/tests/Flow",
    "src/bridge/openapi/specification/src/Flow",
    "src/bridge/openapi/specification/tests/Flow",
    "src/bridge/symfony/http-foundation/src/Flow",
    "src/bridge/symfony/http-foundation/tests/Flow",
    "src/cli/src/Flow",
    "src/cli/tests/Flow",
    "src/core/etl/src/Flow",
    "src/core/etl/tests/Flow",
    "src/lib/array-dot/src/Flow",
    "src/lib/array-dot/tests/Flow",
    "src/lib/azure-sdk/src/Flow",
    "src/lib/azure-sdk/tests/Flow",
    "src/lib/doctrine-dbal-bulk/src/Flow",
    "src/lib/doctrine-dbal-bulk/tests/Flow",
    "src/lib/dremel/src/Flow",
    "src/lib/dremel/tests/Flow",
    "src/lib/filesystem/src/Flow",
    "src/lib/filesystem/tests/Flow",
    "src/lib/parquet-viewer/src/Flow",
    "src/lib/parquet-viewer/tests/Flow",
    "src/lib/parquet/src/Flow",
    "src/lib/parquet/tests/Flow",
    "src/lib/snappy/src/Flow",
    "src/lib/snappy/tests/Flow",
    "src/lib/types/src/Flow",
    "src/lib/types/tests/Flow",
    "src/tools/documentation/src/Flow",
    "src/tools/documentation/tests/Flow"
]
includes = [
    "vendor",
    "tools/phpunit/vendor"
]
excludes = [
    "src/lib/parquet/src/Flow/Parquet/ThriftModel"
]

πŸ“œ Command Output

Error message:

  src/core/etl/tests/Flow/ETL/Tests/Unit/Row/Entry/MapEntryTest.php:143:53: error[invalid-argument]: Invalid argument type for argument #3 of `Flow\ETL\DSL\map_entry`: expected `Flow\Types\Type<array<('TKey.flow\etl\dsl\map_entry() extends array-key), ('TValue.flow\etl\dsl\map_entry() extends
  mixed)>>`, but found `Flow\Types\Type<array<string, string>>`.

πŸ“‚ PHP Code Sample (If Applicable)

<?php

  declare(strict_types=1);

  /**
   * @template T
   */
  interface Type
  {
      /** @param T $value */
      public function isValid(mixed $value): bool;
  }

  /**
   * @template TKey of array-key
   * @template TValue
   *
   * @param ?array<array-key, mixed> $value
   * @param Type<array<TKey, TValue>> $mapType
   *
   * @return Entry<?array<TKey, TValue>>
   */
  function map_entry(string $name, ?array $value, Type $mapType): Entry
  {
      return new MapEntry($name, $value, $mapType);
  }

  /**
   * @template TKey of array-key
   * @template TValue
   * @return Type<array<TKey, TValue>>
   */
  function type_map(Type $keyType, Type $valueType): Type
  {
      // Implementation
  }
  
  /**
   * @return Type<string>
   */
  function type_string(): Type
  {
      // Implementation
  }


I think mago should infer `TKey=string, TValue=string`
from the `type_map(type_string(), type_string())` argument


(map_entry('strings', ['one' => 'two'], type_map(type_string(), type_string())))->value()

πŸ–₯️ Operating System

macOS

πŸ“¦ How did you install Mago?

Composer (composer require carthage-software/mago)

πŸ“ Additional Context

PHPStan (level 9) handles this pattern without errors.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions