March 22, 2023
https://issues.dlang.org/show_bug.cgi?id=23798

          Issue ID: 23798
           Summary: Type inference should traverse trivial aliases
           Product: D
           Version: D2
          Hardware: x86_64
                OS: Linux
            Status: NEW
          Severity: enhancement
          Priority: P1
         Component: dmd
          Assignee: nobody@puremagic.com
          Reporter: default_357-line@yahoo.de

See also: https://forum.dlang.org/thread/wgvtwckvjyhnbpcuyyqy@forum.dlang.org

In C++, you can infer instantiation through simple alias templates:

```
template <typename T, int M, int N>
struct Matrix {
};

template <typename T>
using Vector3 = Matrix<T, 3, 1>;

template<typename T>
void baz(Vector3<T> vector) {}

int main() {
  baz(Vector3<int>());
}
```

There is nothing special about the parameter being `Vector3<int>`; this also works:

```
baz(Matrix<int, 3, 1>());
```

C++ tries to match `Vector3<T>` with `Matrix<T, int, int>`, notices that `Vector3<T>` is a trivial alias to `Matrix<T, 3, 1>`, and matches with that instead.

If you try to do the analogous thing in D:

```
struct Matrix(T, int M, int N) {}
alias Vector3(T) = Matrix!(T, 3, 1);
void foo(T = Vector3!U, U)(T arg) { }
void main() {
    foo!(Vector3!int, int)(Vector3!int());
    foo(Vector3!int());
}
```

The first call works, but the second fails to infer that `U` can be `int`. D
here should notice that `Vector3(T)` is a trivial alias to another template
instance and do a simple parameter substitution, treating `foo` as equivalent
to `void foo(T = Matrix!(U, 3, 1), U)(T arg)`.

--