Skip to content

Class-level template substitution doesn't propagate to parameter types in type error checker #83

@AJenbo

Description

@AJenbo

PHPantom version

main

Installation method

Built from source

Operating system

Linux x86_64

Editor

Zed

Bug description

When a generic class like HasMany<TRelatedModel, TDeclaringModel>
has a method with @param TRelatedModel $model, and the class is
instantiated with concrete type arguments (e.g.
HasMany<Translation, Tag>), the type error checker does not
substitute TRelatedModel → Translation in the parameter type.
The diagnostic sees "expects TRelatedModel, got Translation" and
fires a false positive.

The completion/hover pipeline already performs class-level template
substitution via build_substitution_map in inheritance.rs, but
the type error diagnostic collector does not apply the same
substitution when comparing argument types against parameter types
on generic class methods.

Reproducer:

/**
 * @template TRelatedModel
 * @template TDeclaringModel
 */
class HasMany {
    /** @param TRelatedModel $model */
    public function save($model): void {}
}

class Translation {}
class Tag {
    /** @return HasMany<Translation, Tag> */
    public function translations(): HasMany { return new HasMany(); }
}

function test(): void {
    $tag = new Tag();
    $translation = new Translation();
    $tag->translations()->save($translation);
    // false positive: "expects TRelatedModel, got Translation"
}

Steps to reproduce

Run diagnostics

Error output or panic trace


.phpantom.toml

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions