Skip to content
This repository was archived by the owner on Nov 20, 2024. It is now read-only.

special case assert initializers and const contexts in prefer_is_empty #2122

Merged
merged 5 commits into from
Jun 2, 2020

Conversation

pq
Copy link
Contributor

@pq pq commented Jun 2, 2020

@@ -129,6 +131,20 @@ class _Visitor extends SimpleAstVisitor<void> {
}
final binaryExpression = search as BinaryExpression;

// Don't lint if we're in an assert initializer.
final assertInitializer =
search.parent.thisOrAncestorOfType<AssertInitializer>();
Copy link
Contributor

Choose a reason for hiding this comment

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

This isn't quite right. I think we need to ignore anything inside any ConstructorInitializer, but only when the constructor has been marked as const.

On the other hand, it's possible that we don't need to test for these cases at all, because inConstantContext might return true in the initializer list of const constructors (and given that one of the test cases is for a non-assert initializer and it passes, I suspect that's true).

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 was hoping to get rid of this check too but inConstantContext is not returning true in the initializer test case 🤔. Checking for assert initializers and testing inConstantContext felt like maybe a sweet spot. (Though kludgey.)

Maybe we can discuss offline?

Copy link
Contributor

Choose a reason for hiding this comment

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

Does inConstantContext return true in the non-assert initializer cases:

class C {
  final bool empty;
  const C(dynamic l) : empty = l.length == 0; // here
  const C.a(this.empty);
  const C.b(dynamic l) : this.a(l.length == 0); // here
}
class E {
  const E(bool b);
}
class F extends E {
  const F(dynamic l) : super(l.length == 0); // here
}

If so, then it sounds like a bug that it doesn't within assert initializers.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It does. I've added some tests too.

@scheglov: thoughts on why this is not working in the assert initializer case?

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't see anything about constructor initializers in the spec.

image

image

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, super. Thank you!

Copy link
Contributor

Choose a reason for hiding this comment

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

That begs the question of why it's returning true in other constructor initializers. According to the spec it seems like it shouldn't be. I think that the inconsistency is pointing out a bug, but I'm not sure what the bug is.

But if inConstantContext should not be returning true in these cases, then we just need to not generate the lint in a constructor initializer where the constructor is marked as const.

Copy link
Contributor

Choose a reason for hiding this comment

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

There is a difference between a constant context, and "constantness requirement". Any expression in constant constructors must be a constant expression, but does not introduce a constant context itself. But once you said const C() : x = const MyClass(...), everything in ... is in the constant context.

It does not look to me that inConstantContext returns true for constructor initializers.

  solo_test_inConstantContext_XXX() {
    parse('''
class C {
  final bool empty;
  const C(dynamic l) : empty = l.length == 0; // 0
  const C.a(this.empty);
  const C.b(dynamic l) : this.a(l.length == 0); // 1
}
class E {
  const E(bool b);
}
class F extends E {
  const F(dynamic l) : super(l.length == 0); // 2
}''');
    assertInContext("length == 0; // 0", false);
    assertInContext("length == 0); // 1", false);
    assertInContext("length == 0); // 2", false);
  }

Copy link
Contributor

Choose a reason for hiding this comment

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

It does not look to me that inConstantContext returns true for constructor initializers.

Thanks for checking!

That's good because it means there's no inconsistency and hence no bug, but it leaves me not understanding why the tests passed when the code only checked inConstantContext.

@pq pq merged commit dfbff42 into master Jun 2, 2020
@pq pq deleted the const_fix branch June 2, 2020 18:37
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Development

Successfully merging this pull request may close these issues.

lint prefer_is_empty: List.isEmpty is not a const expression
4 participants