Skip to content

Can't access generic parameters in a generic alias that don't appear in aliased type #24791

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
ire4ever1190 opened this issue Mar 20, 2025 · 1 comment · May be fixed by #24822
Open

Can't access generic parameters in a generic alias that don't appear in aliased type #24791

ire4ever1190 opened this issue Mar 20, 2025 · 1 comment · May be fixed by #24822

Comments

@ire4ever1190
Copy link
Contributor

Nim Version

Nim Compiler Version 2.3.1 [Linux: amd64]
Compiled at 2025-02-28
Copyright (c) 2006-2025 by Andreas Rumpf

git hash: 7e8a650
active boot switches: -d:release

Description

When accessing a generic field from a generic alias it only allows accessing what it aliases.

import std/options

type
  Foo[D: static int; T] = T
  Bar[D] = Option[D]
  Bizz = Foo[9, string]
  Buzz = Foo[9, Option[string]]

echo Bar[string].D # undeclared field: 'D'
echo Bizz.D # 9
echo Buzz.D # undeclared field: 'D'

The Foo example is a bit more useful since it allows you to attach metadata to types without needing to resort to macros.

Current Output

test.nim(9, 17) Error: undeclared field: 'D'
test.nim(11, 10) Error: undeclared field: 'D'

Expected Output

string
9
9

Known Workarounds

No response

Additional Information

I've tracked the issue down to when it calls readTypeParameter it just skips past the alias if both are generics and so the fields on the alias cant be accessed (unless they share the same name)

@metagn
Copy link
Collaborator

metagn commented Apr 11, 2025

Edit: Forgot there is only ever 1 depth of generic aliases, what I wrote wouldn't work very well. Only the final generic alias or the original generic type can be considered, i.e.:

type
  Foo[A: static int] = object
  Bar[B: static int] = Foo[B]
  Baz[C: static int] = Bar[C]

var x: Baz[123]
echo x.B

B is inaccessible here because the Bar[123] type is removed in handleGenericInvocation, the final type of x is Baz[123] = Foo[123]. We can still make it check both Baz and Foo, probably Foo first for compatibility, but this would be a weird rule.

You might want to use a distinct type like Foo[D: static int; T] = distinct Option[D] instead. Generic aliases tend to break in edge cases like #10220.

Maybe we can recursively check each generic alias before skipping, i.e.:

type
  Foo[A, B: static int] = object
  Bar[A: static int] = Foo[A, A * 2]
  Baz = Bar[123]

var x: Baz
echo x.A
echo x.B

Baz is an alias type, so it's skipped, then it checks if Bar has a param named A or B and uses it if it does, otherwise it skips again to Foo to check if it has the param, so on so forth. This might break code though so instead we could also check from the bottom up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants