I expected it to behave similarly to ParseFile in that it is resilient to errors and returns a best effort result with *ast.BadExpr nodes as necessary.
What did you see instead?
ParseExpr fails hard on any error, returning no results.
For context, this came up as we've been fixing gopls completions to work in the face of certain kinds of syntax errors. When a top down parse fails we try to extract an expression that we can parse. However, we can't use ParseExpr because it is not resilient to errors, so we must use ParseFile and wrap our expression.
I'm not sure we can change ParseExpr since there is likely code depending on the current behavior. Perhaps there is room for something new? Something else that might be useful is an interface that will read an expression and not complain if there is data left after reading the expression. That obviates the need to manually find the end of the expression when extracting from larger context.
parser.ParseExpr doesn't say anything about guaranteeing a nil ast.Expr when err != nil. Clients should be checking the error anyway, so it could still potentially be modified. Another option is to introduce a named type that is type-asserted for the src parameter in ParseExprFrom, like SrcWithOptions or something, but that might be gross.
If we do introduce a new API for a "reentrant" expression parser, an x/ repo like x/parserutil would be a good place. A "reentrant" parser could take a cursor like in astutil, which would allow it to keep track of state, e.g.