-
Notifications
You must be signed in to change notification settings - Fork 25.3k
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(language-service): improve non-callable error message #35271
Conversation
One thing we should start evaluating a design for is isolating error messages in a separate (json) file with unique IDs, descriptions, and even examples. Many modern language tools like tsserver, Rust's compiler, and Shellcheck follow this model. It will also provide a natural way for us to support enabling/disabling particular error messages as users have requested. |
In Ivy, each error already has a unique ID, but description is still generated on the fly. |
@@ -197,15 +197,18 @@ export class AstType implements AstVisitor { | |||
const args = ast.args.map(arg => this.getType(arg)); | |||
const target = this.getType(ast.target !); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ast.target
is of type AST
here, but really it's a MethodCall
AST, of which the receiver is an ImplicitReceiver
.
The MethodCall
AST contains the name of the function call, so it looks like a better fix here is to make a safe cast to retrieve the name.
Alternatively, we could fix the typings upstream. Right now, many parameters are just typed AST
. They should have been more specific.
If we go with the cast, we'll have to account for the other case which is a PropertyRead receiver. Please see next comment =)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, you're right. I'll see if we can type the ast specially.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem with pulling out the name is it only contains the name for the most local AST. So for something like title.toUpperCase()()
, the property read AST name would only give us toUpperCase
, and we would have to continue backing up and reconstruct what we think the source code looks like to get title.toUpperCase()
. For this reason, I think it's better to parse out the source code from the AST span.
af324b5
to
4b60ddd
Compare
6ac9355
to
f58240b
Compare
ptal @kyliau |
const analyzer = new AstType(scope, this.info.query, {event}); | ||
private diagnoseExpression(ast: AST, offset: number, inEvent: boolean) { | ||
const scope = this.getExpressionScope(this.path, inEvent); | ||
const analyzer = new AstType(scope, this.info.query, {inEvent}, this.info.source); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't have to pass in the entire template, because the AST we got from the TemplateAst is actually ASTWithSource, so we already have the expression string here. This info combined with the span of the expression node should be sufficient for us to retrieve the string of interest.
Before we do that though, it might be better to update the type for all ASTs in template_ast.ts
from AST to ASTWithSource. Please let me know if you need more clarification, thank you!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this will work, because AstType may visit child nodes of the AST, which may not be ASTWithSource
s. We could pass the source of just the expression, but I am weary of this it would require using more relative spans. What do you think?
TemplateAst values are currently typed as the base class AST, but they are actually constructed with ASTWithSource. Type them as such, because ASTWithSource gives more information about the consumed expression AST to downstream customers (namely, the expression AST source). Unblocks angular#35271
TemplateAst values are currently typed as the base class AST, but they are actually constructed with ASTWithSource. Type them as such, because ASTWithSource gives more information about the consumed expression AST to downstream customers (namely, the expression AST source). Unblocks #35271 PR Close #35892
f58240b
to
15ca665
Compare
@@ -360,6 +362,8 @@ export class AstType implements AstVisitor { | |||
return this.resolvePropertyRead(this.query.getNonNullableType(this.getType(ast.receiver)), ast); | |||
} | |||
|
|||
private sourceOf(ast: AST): string { return this.source.substring(ast.span.start, ast.span.end); } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You brought up a very good point in https://github.com/angular/angular/pull/35271/files#r390700195
Could you please double check that ast.span
here is relative to the whole template?
I think it might be relative to the expression in the template.
In the test case that you wrote in packages/language-service/test/diagnostics_spec.ts the expression is the template itself so this works. Could you please test this with a template that has multiple expressions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call. Fixed to use absolute spans.
b0e3085
to
93af139
Compare
This commit improves the context of a non-callable function error message by providing the affected call target and its non-callable type.
93af139
to
9aaba49
Compare
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
This commit improves the context of a non-callable function error
message by providing the affected call target and its non-callable type.
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
Does this PR introduce a breaking change?