Skip to content

Analyzer allows accessing statics/members on type aliases alising a type variable. #52812

Open
@lrhn

Description

@lrhn

Dart allows accessing static members and constructors of classes (class/mixin/enum declarations) through type aliases, but only if the type alias doesn't "expand to a type variable" (and then only if it explicitly denotes a class.)

A type alias expands to a type variable if its RHS is a type variable, or it's Q<TypeArgsOpt> where Q is a (possibly qualified) identifier denoting a type alias which expands to a type variable.
(We don't care what the type arguments are, we just follow the name at the head of the type until a non-type-alias is found.)

So a type alias explicitly denotes a non-alias declaration C if its RHS is = Q<TypeArgsOpt>; where Q is an identifier or qualified identifier directly denoting C, or transitively if Q denotes another type alias declaration which then explicitly denotes C.

Further, accessing statics on instantiated type expressions (Q<TypeArgs>) is always an error. If Q<TypeArgs> is a type expression, then the only continuations are constructor tear-offs or invocations, (args), .new(args), .name(args), .new, or .name. Any other follow-up selector is a compile-time error.

Which means you can't do typedef A<T> = T; A<int>.parse("1"); for two reasons: parse is not a constructor, so it can't be invoked on an instantiated type expression at all, and A doesn't denote a class.

Example:

void main() {
  A<C>.named;
  A<C>.stat;
  A<C>.inst;

  C2<int>.stat;
}

extension on Type {
  get inst => 42;
}

class C {
  C();
  C.named();
  static get stat => 0;
}
typedef A<T> = T;

typedef C2<T> = C;

The front end gives the following errors (from dartpad.dev).:

lib/main.dart:3:3:
Error: Can't use a typedef denoting a type variable as a constructor, nor for a static member access.
  A<C>.named;
  ^
lib/main.dart:19:11:
Info: This is the type variable ultimately denoted.
typedef A<T> = T;
          ^
lib/main.dart:4:3:
Error: Can't use a typedef denoting a type variable as a constructor, nor for a static member access.
  A<C>.stat;
  ^
lib/main.dart:19:11:
Info: This is the type variable ultimately denoted.
typedef A<T> = T;
          ^
lib/main.dart:5:3:
Error: Can't use a typedef denoting a type variable as a constructor, nor for a static member access.
  A<C>.inst;
  ^
lib/main.dart:19:11:
Info: This is the type variable ultimately denoted.
typedef A<T> = T;
          ^
lib/main.dart:7:11:
Error: Cannot access static member on an instantiated generic class.
  C2<int>.stat;
          ^^^^
lib/main.dart:3:8:
Error: The getter 'named' isn't defined for the class 'Type'.
 - 'Type' is from 'dart:core'.
  A<C>.named;
       ^^^^^
lib/main.dart:4:8:
Error: The getter 'stat' isn't defined for the class 'Type'.
 - 'Type' is from 'dart:core'.
  A<C>.stat;
       ^^^^
Error: Compilation failed.

which is one error per place the term A<C> is used as receiver for a member access, and one where C2<int> is used.
(Plus two spurious errors where it seems to try doing the access on a Type object instead, which shouldn't happen.)

The analyzer gives only one error:

error
line 7 • The static member 'stat' can't be accessed on a class instantiation.
Try removing the type arguments from the class name, or changing the member name to the name of a constructor.
info
line 11 • The declaration 'inst' isn't referenced.
Try removing the declaration of 'inst'.

(and one info, saying that the extension method inst isn't used, which is doubly weird).

Something is going wrong with errors about accessing members through type aliases which expands to a type variable.
The analyzer correctly recognizes that C2<int>.stat is not allowed, but not that A<C>.stat is not allowed for the same reason, and for another reason too.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3A lower priority bug or feature requestarea-dart-modelFor issues related to conformance to the language spec in the parser, compilers or the CLI analyzer.dart-model-analyzer-specIssues with the analyzer's implementation of the language spectype-bugIncorrect behavior (everything from a crash to more subtle misbehavior)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions