Skip to content
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

feat(compiler-cli): explain why an expression cannot be used in AOT compilations #37587

Closed
wants to merge 4 commits into from

Conversation

@JoostK
Copy link
Member

@JoostK JoostK commented Jun 15, 2020

During AOT compilation, the value of some expressions need to be known at
compile time. The compiler has to ability to statically evaluate expressions
the best it can, but there can be occurrences when an expression cannot be
evaluated statically. For instance, the evaluation could depend on a dynamic
value or syntax is used that the compiler does not understand. Alternatively,
it is possible that an expression could be statically evaluated but the
resulting value would be of an incorrect type.

In these situations, it would be helpful if the compiler could explain why it
is unable to evaluate an expression. To this extend, the static interpreter
in Ivy keeps track of a trail of DynamicValues which follow the path of nodes
that were considered all the way to the node that causes an expression to be
considered dynamic. Up until this commit, this rich trail of information was
not surfaced to a developer so the compiler was of little help to explain
why static evaluation failed, resulting in situations that are hard to debug
and resolve.

This commit adds much more insight to the diagnostic that is produced for static
evaluation errors. For dynamic values, the trail of DynamicValue instances
is presented to the user in a meaningful way. If a value is available but not
of the correct type, the type of the resolved value is shown.

Resolves FW-2155


Screenshot 2020-06-15 at 13 07 14

Screenshot 2020-06-15 at 13 11 56

Screenshot 2020-06-15 at 13 15 46

if (maxDepth === 0) {
return 'Array';
}
return `[${value.map(v => describeResolvedType(v, maxDepth - 1)).join(', ')}]`;
Copy link
Member Author

@JoostK JoostK Jun 15, 2020

Choose a reason for hiding this comment

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

I choose to display arrays as a tuple representation (e.g. [string, string, number]), but we may as well choose to show them as array with a union type (e.g. (string | number)[]). Alternatively, we could limit the number of entries to include.

Loading

@JoostK JoostK marked this pull request as ready for review Jun 15, 2020
@pullapprove pullapprove bot requested review from alxhub and gkalpak Jun 15, 2020
alxhub
alxhub approved these changes Jun 15, 2020
Copy link
Contributor

@alxhub alxhub left a comment

👍 really clean implementation - this is going to be awesome!

Loading

@JoostK JoostK force-pushed the explain-dynamic-values branch from 7dd2242 to 03b3bb6 Jun 15, 2020
Copy link
Member

@gkalpak gkalpak left a comment

A couple of optional nits and a couple of commit message typos. Otherwise looks great 💯

  • 2nd commit: has to ability to statically evaluate --> has the ability to statically evaluate (?)
  • 3rd commit: a function calls --> a function call

Loading

@@ -55,6 +56,11 @@ export const enum DynamicValueReason {
*/
INVALID_EXPRESSION_TYPE,

/**
* A function call could not be evaluated as its body is not a single return statement.
Copy link
Member

@gkalpak gkalpak Jun 17, 2020

Choose a reason for hiding this comment

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

Nit: The current wording makes it sound as if the call has a body 😇

Suggested change
* A function call could not be evaluated as its body is not a single return statement.
* A function call could not be evaluated as the function's body is not a single return statement.

Loading

} else if (value instanceof ResolvedModule) {
return 'module';
} else if (value instanceof EnumValue) {
return value.enumRef.debugName ?? '(anonymous)';
Copy link
Member

@gkalpak gkalpak Jun 17, 2020

Choose a reason for hiding this comment

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

Would it make sense to include something to show it is an enum value?

Loading

Copy link
Member Author

@JoostK JoostK Jun 17, 2020

Choose a reason for hiding this comment

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

Enum values are essentially just References, but refer to a particular member of that enum. As we're just printing the type here, only the information from the reference is used. As such, it's displayed as other References would be. We could include the kind of declaration for any Reference, e.g. show class MyCmp and enum ViewEncapsulation, but I kept the notation as close as TS's native representation of types.

What might make sense to do is to extend createValueHasWrongTypeError such that it creates a ts.DiagnosticRelationInformation pointing to the declaration of the enum, as it does for References.

Loading

}
return `[${value.map(v => describeResolvedType(v, maxDepth - 1)).join(', ')}]`;
} else if (value instanceof DynamicValue) {
return 'dynamic';
Copy link
Member

@gkalpak gkalpak Jun 17, 2020

Choose a reason for hiding this comment

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

Nit: I am wondering whether dynamic is somewhat ambiguous for the user. Would something like not statically analyzable be more helpful?

Loading

Copy link
Member Author

@JoostK JoostK Jun 17, 2020

Choose a reason for hiding this comment

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

Good point, changed as proposed. I also went over all others and added parenthesis to some to indicate that these are not actual types.

Loading

@alxhub
Copy link
Contributor

@alxhub alxhub commented Jun 17, 2020

Loading

JoostK added 3 commits Jun 18, 2020
…dInformation`

Previously, an anonymous type was used for creating a diagnostic with related
information. The anonymous type would then be translated into the necessary
`ts.DiagnosticRelatedInformation` shape within `makeDiagnostic`. This commit
switches the `makeDiagnostic` signature over to taking `ts.DiagnosticRelatedInformation`
directly and introduces `makeRelatedInformation` to easily create such objects.
This is done to aid in making upcoming work more readable.
…ompilations

During AOT compilation, the value of some expressions need to be known at
compile time. The compiler has the ability to statically evaluate expressions
the best it can, but there can be occurrences when an expression cannot be
evaluated statically. For instance, the evaluation could depend on a dynamic
value or syntax is used that the compiler does not understand. Alternatively,
it is possible that an expression could be statically evaluated but the
resulting value would be of an incorrect type.

In these situations, it would be helpful if the compiler could explain why it
is unable to evaluate an expression. To this extend, the static interpreter
in Ivy keeps track of a trail of `DynamicValue`s which follow the path of nodes
that were considered all the way to the node that causes an expression to be
considered dynamic. Up until this commit, this rich trail of information was
not surfaced to a developer so the compiler was of little help to explain
why static evaluation failed, resulting in situations that are hard to debug
and resolve.

This commit adds much more insight to the diagnostic that is produced for static
evaluation errors. For dynamic values, the trail of `DynamicValue` instances
is presented to the user in a meaningful way. If a value is available but not
of the correct type, the type of the resolved value is shown.

Resolves FW-2155
This commit introduces a dedicated `DynamicValue` kind to indicate that a value
cannot be evaluated statically as the function body is not just a single return
statement. This allows more accurate reporting of why a function call failed
to be evaluated, i.e. we now include a reference to the function declaration
and have a tailor-made diagnostic message.
@JoostK JoostK force-pushed the explain-dynamic-values branch from df5bd6f to 3f8660b Jun 18, 2020
@alxhub
Copy link
Contributor

@alxhub alxhub commented Jun 19, 2020

Loading

AndrewKushnir added a commit that referenced this issue Jun 25, 2020
…ompilations (#37587)

During AOT compilation, the value of some expressions need to be known at
compile time. The compiler has the ability to statically evaluate expressions
the best it can, but there can be occurrences when an expression cannot be
evaluated statically. For instance, the evaluation could depend on a dynamic
value or syntax is used that the compiler does not understand. Alternatively,
it is possible that an expression could be statically evaluated but the
resulting value would be of an incorrect type.

In these situations, it would be helpful if the compiler could explain why it
is unable to evaluate an expression. To this extend, the static interpreter
in Ivy keeps track of a trail of `DynamicValue`s which follow the path of nodes
that were considered all the way to the node that causes an expression to be
considered dynamic. Up until this commit, this rich trail of information was
not surfaced to a developer so the compiler was of little help to explain
why static evaluation failed, resulting in situations that are hard to debug
and resolve.

This commit adds much more insight to the diagnostic that is produced for static
evaluation errors. For dynamic values, the trail of `DynamicValue` instances
is presented to the user in a meaningful way. If a value is available but not
of the correct type, the type of the resolved value is shown.

Resolves FW-2155

PR Close #37587
AndrewKushnir added a commit that referenced this issue Jun 25, 2020
…all (#37587)

This commit introduces a dedicated `DynamicValue` kind to indicate that a value
cannot be evaluated statically as the function body is not just a single return
statement. This allows more accurate reporting of why a function call failed
to be evaluated, i.e. we now include a reference to the function declaration
and have a tailor-made diagnostic message.

PR Close #37587
ngwattcos added a commit to ngwattcos/angular that referenced this issue Jun 25, 2020
…dInformation` (angular#37587)

Previously, an anonymous type was used for creating a diagnostic with related
information. The anonymous type would then be translated into the necessary
`ts.DiagnosticRelatedInformation` shape within `makeDiagnostic`. This commit
switches the `makeDiagnostic` signature over to taking `ts.DiagnosticRelatedInformation`
directly and introduces `makeRelatedInformation` to easily create such objects.
This is done to aid in making upcoming work more readable.

PR Close angular#37587
ngwattcos added a commit to ngwattcos/angular that referenced this issue Jun 25, 2020
…ompilations (angular#37587)

During AOT compilation, the value of some expressions need to be known at
compile time. The compiler has the ability to statically evaluate expressions
the best it can, but there can be occurrences when an expression cannot be
evaluated statically. For instance, the evaluation could depend on a dynamic
value or syntax is used that the compiler does not understand. Alternatively,
it is possible that an expression could be statically evaluated but the
resulting value would be of an incorrect type.

In these situations, it would be helpful if the compiler could explain why it
is unable to evaluate an expression. To this extend, the static interpreter
in Ivy keeps track of a trail of `DynamicValue`s which follow the path of nodes
that were considered all the way to the node that causes an expression to be
considered dynamic. Up until this commit, this rich trail of information was
not surfaced to a developer so the compiler was of little help to explain
why static evaluation failed, resulting in situations that are hard to debug
and resolve.

This commit adds much more insight to the diagnostic that is produced for static
evaluation errors. For dynamic values, the trail of `DynamicValue` instances
is presented to the user in a meaningful way. If a value is available but not
of the correct type, the type of the resolved value is shown.

Resolves FW-2155

PR Close angular#37587
ngwattcos added a commit to ngwattcos/angular that referenced this issue Jun 25, 2020
…all (angular#37587)

This commit introduces a dedicated `DynamicValue` kind to indicate that a value
cannot be evaluated statically as the function body is not just a single return
statement. This allows more accurate reporting of why a function call failed
to be evaluated, i.e. we now include a reference to the function declaration
and have a tailor-made diagnostic message.

PR Close angular#37587
AndrewKushnir added a commit to AndrewKushnir/angular that referenced this issue Jun 25, 2020
…nction call (angular#37587)"

This reverts commit ce879fc.

Reason for revert: failing tests on Windows (related to file paths).
AndrewKushnir added a commit to AndrewKushnir/angular that referenced this issue Jun 25, 2020
…in AOT compilations (angular#37587)"

This reverts commit 712f1bd.

Reason for revert: failing tests on Windows (related to file paths).
AndrewKushnir added a commit to AndrewKushnir/angular that referenced this issue Jun 25, 2020
…icRelatedInformation` (angular#37587)"

This reverts commit d2fb552.

Reason for revert: failing tests on Windows (related to file paths).
@angular-automatic-lock-bot
Copy link

@angular-automatic-lock-bot angular-automatic-lock-bot bot commented Jul 26, 2020

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

Loading

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Jul 26, 2020
alxhub added a commit that referenced this issue Jul 30, 2020
…dInformation` (#37587)

Previously, an anonymous type was used for creating a diagnostic with related
information. The anonymous type would then be translated into the necessary
`ts.DiagnosticRelatedInformation` shape within `makeDiagnostic`. This commit
switches the `makeDiagnostic` signature over to taking `ts.DiagnosticRelatedInformation`
directly and introduces `makeRelatedInformation` to easily create such objects.
This is done to aid in making upcoming work more readable.

PR Close #37587
profanis added a commit to profanis/angular that referenced this issue Sep 5, 2020
…dInformation` (angular#37587)

Previously, an anonymous type was used for creating a diagnostic with related
information. The anonymous type would then be translated into the necessary
`ts.DiagnosticRelatedInformation` shape within `makeDiagnostic`. This commit
switches the `makeDiagnostic` signature over to taking `ts.DiagnosticRelatedInformation`
directly and introduces `makeRelatedInformation` to easily create such objects.
This is done to aid in making upcoming work more readable.

PR Close angular#37587
profanis added a commit to profanis/angular that referenced this issue Sep 5, 2020
…ompilations (angular#37587)

During AOT compilation, the value of some expressions need to be known at
compile time. The compiler has the ability to statically evaluate expressions
the best it can, but there can be occurrences when an expression cannot be
evaluated statically. For instance, the evaluation could depend on a dynamic
value or syntax is used that the compiler does not understand. Alternatively,
it is possible that an expression could be statically evaluated but the
resulting value would be of an incorrect type.

In these situations, it would be helpful if the compiler could explain why it
is unable to evaluate an expression. To this extend, the static interpreter
in Ivy keeps track of a trail of `DynamicValue`s which follow the path of nodes
that were considered all the way to the node that causes an expression to be
considered dynamic. Up until this commit, this rich trail of information was
not surfaced to a developer so the compiler was of little help to explain
why static evaluation failed, resulting in situations that are hard to debug
and resolve.

This commit adds much more insight to the diagnostic that is produced for static
evaluation errors. For dynamic values, the trail of `DynamicValue` instances
is presented to the user in a meaningful way. If a value is available but not
of the correct type, the type of the resolved value is shown.

Resolves FW-2155

PR Close angular#37587
profanis added a commit to profanis/angular that referenced this issue Sep 5, 2020
…all (angular#37587)

This commit introduces a dedicated `DynamicValue` kind to indicate that a value
cannot be evaluated statically as the function body is not just a single return
statement. This allows more accurate reporting of why a function call failed
to be evaluated, i.e. we now include a reference to the function declaration
and have a tailor-made diagnostic message.

PR Close angular#37587
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

5 participants