language icon indicating copy to clipboard operation
language copied to clipboard

Macros: ergonomics of type checking (StaticType) in the current API

Open GregoryConrad opened this issue 1 year ago • 2 comments

See this comment from some time ago for a little context. CC @jakemac53

I was recently trying to create a macro and realized it is pretty painful (I ended giving up in the moment) on checking whether some TypeAnnotation is the same type as a type defined in an external package. I ended up using String equality on the types' names, which is obviously incorrect.

Since resolving a type via its library's Uri is not the safest option (and is @Deprecated because of that), perhaps a better option would be to repurpose Type (see https://github.com/dart-lang/language/issues/2393) so that it can be used to reference a type's StaticType. A compelling API could look something like the following:

import 'packages:flutter/widgets.dart';

builder.resolve(myTypeAnnotation.code).isExactly(Widget.staticType) // perhaps backwards compatible
// or even:
builder.resolve(myTypeAnnotation.code).isExactly(Widget) // maybe not backwards compatible, but nicer API

This:

  1. Solves the entire "is this type transitively included" problem, since it must be imported in the macro itself in order to reference the type (Widget above)
  2. Improves the ergonomics of type-checking tenfold, and doesn't rely on a handwritten Uri

GregoryConrad avatar Feb 02 '24 18:02 GregoryConrad

Something similar would also be extremely helpful in DeclarationCode.fromParts; take:

      [
        'Widget',
        ' build(',
        ...['BuildContext', ' ', contextName, ', '],
        ') => ',
        ...[functionName, '(', functionArgs, ');'],
      ],

The above would be much more elegant/error-free with (an example):

      [
        Widget.code,
        ' build(',
        ...[BuildContext.code, ' ', contextName, ', '],
        ') => ',
        ...[functionName, '(', functionArgs, ');'],
      ],

When you start to consider all of the types generated code will need to reference, this adds up really quick. Also, if there's no API that makes referencing external types easy, I'd bet many folks would resort to strings directly, which comes with its own bag of problems.

GregoryConrad avatar Feb 04 '24 18:02 GregoryConrad

The current API is definitely quite verbose, no argument from me there.

We can't use Type instances directly, it just isn't feasible to do, because those types you are referencing do not exist in the compiler/analyzer isolate, only in the macro isolate (most likely at least).

My personal favorite proposal so far relating to this is reflected imports. That gives you a way of doing something similar to a normal import, but it gives you identifiers to the references from that library instead of a regular reference.

That doesn't fully solve all the verbosity, getting a StaticType is still a bit cumbersome, but it does solve part of it.

jakemac53 avatar Feb 05 '24 15:02 jakemac53