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

Re-do error handling #12

Merged
merged 2 commits into from
Jul 9, 2020
Merged

Re-do error handling #12

merged 2 commits into from
Jul 9, 2020

Conversation

sunshowers
Copy link
Contributor

@sunshowers sunshowers commented Jul 8, 2020

Remove panics caused by file load or parsing errors.

This requires a new data model for errors, with a couple of new types.

Fixes #11.

(Could you do a new release once this is accepted? Thanks!)

Remove panics caused by file load or parsing errors.

This requires a new data model for errors, with a couple of new types.
Comment on lines +353 to +361
);
assert_eq!(error.module_name(), "invalid");
assert_eq!(error.src_span().start().line, 2);
assert_eq!(error.src_span().start().column, 0);
assert_eq!(error.src_span().end().line, 2);
assert_eq!(error.src_span().end().column, 12);
assert_eq!(error.path(), Path::new("src/invalid.rs"));
match error.kind() {
ErrorKind::Parse(_) => {}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This would previously panic but now adds an error to the list.

Copy link
Owner

Choose a reason for hiding this comment

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

Love the added detail in the test cases. Do you think it's worth having separate test cases for the different errors that can arise when accessing the root file?

@sunshowers
Copy link
Contributor Author

Ahh, looks like CI is failing on Rust 1.32. Would you be willing to consider bumping the MSRV to 1.40 (for #[non_exhaustive]) given that this is a breaking change anyway?

Copy link
Owner

@TedDriggs TedDriggs left a comment

Choose a reason for hiding this comment

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

Thanks for doing this, and I love the high-level approach. There are a few minor nits and some naming questions, but I think we can get this merged and shipped this week.

@@ -61,8 +63,8 @@ impl InlinerBuilder {
self
}

/// Configures whether unexpanded modules (due to a missing file) will lead
/// to an `Err` return value or not.
/// Configures whether unexpanded modules (due to missing files or invalid Rust sourcd code)
Copy link
Owner

Choose a reason for hiding this comment

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

Suggested change
/// Configures whether unexpanded modules (due to missing files or invalid Rust sourcd code)
/// Configures whether unexpanded modules (due to missing files or invalid Rust source code)

Nit: Fixed typo.

@@ -88,42 +90,167 @@ impl InlinerBuilder {
};
let result =
Visitor::<R>::with_resolver(src_file, self.root, errors.as_mut(), Cow::Owned(resolver))
.visit();
.visit()
.map_err(|kind| Error::Initial(kind))?;
Copy link
Owner

Choose a reason for hiding this comment

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

Suggested change
.map_err(|kind| Error::Initial(kind))?;
.map_err(Error::Initial)?;

Minor change to keep clippy happy.

/// An error happened while reading or parsing the initial file.
///
/// For example, the initial file wasn't found or wasn't a valid Rust file.
Initial(ErrorKind),
Copy link
Owner

Choose a reason for hiding this comment

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

I keep tripping over the names of these two enum variants. How would you feel about this variant being called Root?

Parse(syn::Error),
}

impl From<std::io::Error> for ErrorKind {
Copy link
Owner

Choose a reason for hiding this comment

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

Aside: I have a crate, from_variants that generates these automatically. Might be overkill for just two of them.

Comment on lines +353 to +361
);
assert_eq!(error.module_name(), "invalid");
assert_eq!(error.src_span().start().line, 2);
assert_eq!(error.src_span().start().column, 0);
assert_eq!(error.src_span().end().line, 2);
assert_eq!(error.src_span().end().column, 12);
assert_eq!(error.path(), Path::new("src/invalid.rs"));
match error.kind() {
ErrorKind::Parse(_) => {}
Copy link
Owner

Choose a reason for hiding this comment

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

Love the added detail in the test cases. Do you think it's worth having separate test cases for the different errors that can arise when accessing the root file?

_private: (),
/// An error that was encountered while reading, parsing or inlining a module.
#[derive(Debug)]
#[non_exhaustive]
Copy link
Owner

Choose a reason for hiding this comment

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

If we omit the use of this attribute, should this otherwise work on 1.32.0? Despite having written multiple proc-macro crates, I've never really gotten my head around how rustc versions and proc-macros interact, so I'm not sure if bumping the min-version of this crate would lead to its dependent crates also having to bump their rustc version.

If removing this attribute lets us keep 1.32.0 at the expense of requiring a minor version bump for the next error case that comes along, I think that'd be an acceptable tradeoff. I think you've been thoughtful enough in covering the cases that I don't think it's likely we'll need more any time soon.

/// Configures whether unexpanded modules (due to a missing file) will lead
/// to an `Err` return value or not.
/// Configures whether unexpanded modules (due to missing files or invalid Rust sourcd code)
/// will lead to an `Err` return value or not.
///
/// Default: `false`.
pub fn error_not_found(&mut self, error_not_found: bool) -> &mut Self {
Copy link
Owner

Choose a reason for hiding this comment

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

Should this be changed to report_errors or something? It's not just about cases where the file isn't found.


/// Returns the `Span` (including line and column information) in the source path that caused
/// `self.path()` to be included.
pub fn src_span(&self) -> proc_macro2::Span {
Copy link
Owner

Choose a reason for hiding this comment

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

Suggested change
pub fn src_span(&self) -> proc_macro2::Span {
pub fn src_span(&self) -> Span {

If you were deliberately fully qualifying the path here for rustdoc's benefit, feel free to ignore this suggestion. Otherwise, since we have the type locally imported it seems cleaner not to repeat the crate name.

@@ -18,33 +18,38 @@ pub(crate) struct Visitor<'a, R: Clone> {
/// a direct file-system dependency so the expander can be tested.
resolver: Cow<'a, R>,
/// A log of module items that weren't expanded.
not_found_log: Option<&'a mut Vec<(String, SourceLocation)>>
inline_error_log: Option<&'a mut Vec<InlineError>>,
Copy link
Owner

Choose a reason for hiding this comment

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

Nit: Should this just be called error_log?

InlinerBuilder::default()
.parse_and_inline_modules(src_file)
.unwrap()
pub fn parse_and_inline_modules(src_file: &std::path::Path) -> Result<syn::File, Error> {
Copy link
Owner

Choose a reason for hiding this comment

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

Returning syn::File instead of a result was based on the signature from dtolnay/request-for-implementation#6. Since I operate on the belief that @dtolnay knows a lot more than me and has good reasons for most of his suggestions, how would you feel about leaving this signature as-is and adding try_parse_and_inline_modules or something as a sibling public function?

Copy link
Owner

Choose a reason for hiding this comment

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

Found the reason why this is infallible here.

I'm leaning towards leaving this function as-is, but updating its documentation and/or the crate documentation to make clearer that there's a way to build an inliner that will preserve/return errors found during inlining.


/// The initial file was successfully loaded, but some errors happened while attempting to
/// inline modules.
Inline(Vec<InlineError>),
Copy link
Owner

Choose a reason for hiding this comment

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

Based on this conversation, I wonder if this should be Error::Incomplete(IncompleteInlining) where IncompleteInlining is:

#[non_exhaustive]
pub struct IncompleteInlining {
    pub file: syn::File,
    pub errors: Vec<InlineError>,
}

That way a caller can still get whatever succeeded and have the errors.

TedDriggs added a commit that referenced this pull request Jul 8, 2020
* Preserve signature of parse_and_inline_modules
* Add IncompleteInlining to report errors during recursion
* Improve doc comments for parse_and_inline_modules

Relates to #11
Amends #12
@TedDriggs TedDriggs merged commit a6b902c into TedDriggs:master Jul 9, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Don't panic on file read/open/parse errors
2 participants