Skip to content

Conversation

@matanlurey
Copy link
Contributor

This will be nice to have versus stuffed into the AngularDart compiler, and it doesn't feel "right" going into a library like build, which I think benefits from having a very small interface and low-threshold for changes.

Advantages of this approach

  • Adds an "approved" (not `/lib/src/annotations.dart') way of performing checks.
  • Has two backing implementations not based on dart:mirrors (for long-term safety).
  • Easy re-usable setup for complex compilers like inject or angular.

See type_checker_test.dart for some functional tests.

Closes #136.

@thosakwe
Copy link

I just saw this PR. This might also close #155 (which I just opened). I'll have to check...

@kevmoo
Copy link
Member

kevmoo commented Jun 19, 2017

@matanlurey I like...but!

I noticed when trying to convert the JsonSerialiableGenerator to it it blows up w/ the dynamic element – which (for some reason) has no source.

If you could – check it out. Or I'll do a follow-up. It's certainly better than the hacks I have in place to detect DateTime, Iterable, and List

@matanlurey
Copy link
Contributor Author

@kevmoo Let me try converting your generator as a test case then.

@kevmoo
Copy link
Member

kevmoo commented Jun 19, 2017 via email

@matanlurey
Copy link
Contributor Author

@kevmoo Just updated, and added annotationOf which seems to work fine:

String _fieldToJsonMapKey(String fieldName, FieldElement field) {
  const $JsonKey = const TypeChecker.fromRuntime(JsonKey);
  var jsonKey = $JsonKey.annotationOf(field);
  if (jsonKey != null) {
    var jsonName = jsonKey.getField('jsonName').toStringValue();
    return jsonName;
  }
  return fieldName;
}

Copy link
Member

@kevmoo kevmoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM – let's see what @jakemac53 says...

@kevmoo
Copy link
Member

kevmoo commented Jun 19, 2017

See broken build – Cannot resolve "asset:source_gen/lib/generators/json_serializable.dart".

Ugh...

/// Returns the first constant annotating [element] that is this type.
///
/// Otherwise returns `null`.
DartObject annotationOf(Element element) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be firstAnnotationOf? And then possibly add annotationsOf?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

}

/// Returns `true` if representing the exact same class as [element].
bool isExactly(Element element);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be ClassElement?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. Originally I had it, but I changed because:

  1. Most APIs return Element, not ClassElement, and this avoids users having to cast all over.
  2. There are other types not yet covered (like Function types) that are not classes but could be used here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, sgtm

element is ClassElement && element.allSupertypes.any(isExactlyType);

/// Returns `true` if representing a super type of [staticType].
bool isSuperType(DartType staticType) => isSuperOf(staticType.element);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: isSuperTypeOf for consistency

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


/// An abstraction around doing static type checking at compile/build time.
abstract class TypeChecker {
const TypeChecker._();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need this constructor? You should be able to delete it and remove the super constructor calls.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could remove it, but then the other classes couldn't be const. Since I wanted that anyway, I figured making the TypeChecker class itself not extendable is probably an OK thing to do.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok just for the const, makes sense. We can always make this public later if somebody actually has a valid reason to extend it and files an issue.

bool isSuperOf(Element element) =>
isExactly(element) ||
element is ClassElement &&
element.allSupertypes.any((t) => t.element == _type.element);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the logic different for checking super types? (here it checks for ClassElement equality where isExactly checks for DartType equality)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, thanks!

fragment: MirrorSystem.getName(mirror.simpleName),
);
default:
throw new StateError('Cannot resolve "$sourceUri".');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe add an additional note You must import the ${mirror.simpleName} class using a package: or dart: uri..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

var sourceUri = element.source.uri;
switch (sourceUri.scheme) {
case 'dart':
if (sourceUri.pathSegments.isNotEmpty) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it an error if this is empty? Also when is it more than one segment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a comment why.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where? (maybe forgot to push a commit?)


final core = resolver.getLibraryByName('dart.core');
staticMap = core.getType('Map').type;
staticMapChecker = new TypeChecker.fromStatic(staticMap);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might as well just create this inline in the test that uses them below like the others instead of creating them for all tests (same for staticHashMapChecker).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only reason I did this is to avoid creating a Resolver multiple times per test.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh right, setUpAll just runs once doesn't it, sgtm

});

test('should not be a super type of dart:core#Map', () {
expect(checkMap().isSuperType(staticMap), isTrue);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be isFalse?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done and fixed.

expect(
checkMap().isExactlyType(staticMap),
isTrue,
reason: '$checkMap != $staticMap',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: no trailing comma ;) (also below).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Contributor

@jakemac53 jakemac53 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally LGTM, but it would be good to also add tests for non-core classes if you don't mind.

}

/// Returns `true` if representing the exact same class as [element].
bool isExactly(Element element);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, sgtm

@matanlurey
Copy link
Contributor Author

As discussed offline with @jakemac53, filed #161 to add additional test cases - need some infra build-out for pkg/build_test first.

@kevmoo
Copy link
Member

kevmoo commented Jun 19, 2017

@matanlurey thoughts on the broken travis bits?

@matanlurey
Copy link
Contributor Author

@kevmoo Fixing now, I had some mismatch b/w asset: and package: URLs.

New functionality normalizes the two (internally). Will upload as soon as all tests pass.

kevmoo added a commit that referenced this pull request Jun 19, 2017
@kevmoo
Copy link
Member

kevmoo commented Jun 19, 2017

@matanlurey for this PR or later – would be great to have a isExactlyOrIsSuperTypeOf – or similar.

See 0046bdd#diff-c4274d5939b2f855cfba15318f2d42ebR250

Having to do isExact || isSuper several places

@matanlurey
Copy link
Contributor Author

@kevmoo Send a PR after I merge? I finally got this one green :P

@kevmoo
Copy link
Member

kevmoo commented Jun 19, 2017

Send a PR after I merge? I finally got this one green :P

Deal. 👍

@matanlurey matanlurey merged commit d498497 into dart-lang:master Jun 19, 2017
@matanlurey matanlurey deleted the static_types branch June 19, 2017 19:53
kevmoo added a commit that referenced this pull request Jun 19, 2017
mosuem pushed a commit to dart-lang/build that referenced this pull request Dec 10, 2024
* Add TypeChecker class.

* Added annotationOf.

* Added a fallback case for dynamic.

* Address comments.

* Normalize.

* Dartfmt.
mosuem pushed a commit to dart-lang/build that referenced this pull request Dec 10, 2024
* Add TypeChecker class.

* Added annotationOf.

* Added a fallback case for dynamic.

* Address comments.

* Normalize.

* Dartfmt.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants