diff options
| author | Taylor Cramer <cramertj@google.com> | 2017-11-27 18:14:24 -0800 |
|---|---|---|
| committer | Taylor Cramer <cramertj@google.com> | 2017-12-19 14:58:51 -0800 |
| commit | 07f51fb8684e1ea0a3859234d360814093d891bd (patch) | |
| tree | 2ba4570ab672999453ebbf0d15610392a086d044 /src/libsyntax/parse | |
| parent | b39c4bc12358078f77ddd01288b24252f757f37d (diff) | |
| download | rust-07f51fb8684e1ea0a3859234d360814093d891bd.tar.gz rust-07f51fb8684e1ea0a3859234d360814093d891bd.zip | |
Implement non-mod.rs mod statements
Diffstat (limited to 'src/libsyntax/parse')
| -rw-r--r-- | src/libsyntax/parse/lexer/mod.rs | 1 | ||||
| -rw-r--r-- | src/libsyntax/parse/mod.rs | 9 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 132 |
3 files changed, 99 insertions, 43 deletions
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 1e84fb98a66..9828995362a 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1754,6 +1754,7 @@ mod tests { included_mod_stack: RefCell::new(Vec::new()), code_map: cm, missing_fragment_specifiers: RefCell::new(HashSet::new()), + non_modrs_mods: RefCell::new(vec![]), } } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 4d435665d3c..89a54989f96 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -47,6 +47,9 @@ pub struct ParseSess { pub unstable_features: UnstableFeatures, pub config: CrateConfig, pub missing_fragment_specifiers: RefCell<HashSet<Span>>, + // Spans where a `mod foo;` statement was included in a non-mod.rs file. + // These are used to issue errors if the non_modrs_mods feature is not enabled. + pub non_modrs_mods: RefCell<Vec<(ast::Ident, Span)>>, /// Used to determine and report recursive mod inclusions included_mod_stack: RefCell<Vec<PathBuf>>, code_map: Rc<CodeMap>, @@ -70,6 +73,7 @@ impl ParseSess { missing_fragment_specifiers: RefCell::new(HashSet::new()), included_mod_stack: RefCell::new(vec![]), code_map, + non_modrs_mods: RefCell::new(vec![]), } } @@ -86,7 +90,10 @@ pub struct Directory { #[derive(Copy, Clone)] pub enum DirectoryOwnership { - Owned, + Owned { + // None if `mod.rs`, `Some("foo")` if we're in `foo.rs` + relative: Option<ast::Ident>, + }, UnownedViaBlock, UnownedViaMod(bool /* legacy warnings? */), } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c3dd17e8775..d6f09cd85d7 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -514,7 +514,10 @@ impl<'a> Parser<'a> { restrictions: Restrictions::empty(), obsolete_set: HashSet::new(), recurse_into_file_modules, - directory: Directory { path: PathBuf::new(), ownership: DirectoryOwnership::Owned }, + directory: Directory { + path: PathBuf::new(), + ownership: DirectoryOwnership::Owned { relative: None } + }, root_module_name: None, expected_tokens: Vec::new(), token_cursor: TokenCursor { @@ -5731,7 +5734,7 @@ impl<'a> Parser<'a> { fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) { if let Some(path) = attr::first_attr_value_str_by_name(attrs, "path") { self.directory.path.push(&path.as_str()); - self.directory.ownership = DirectoryOwnership::Owned; + self.directory.ownership = DirectoryOwnership::Owned { relative: None }; } else { self.directory.path.push(&id.name.as_str()); } @@ -5742,10 +5745,28 @@ impl<'a> Parser<'a> { } /// Returns either a path to a module, or . - pub fn default_submod_path(id: ast::Ident, dir_path: &Path, codemap: &CodeMap) -> ModulePath { + pub fn default_submod_path( + id: ast::Ident, + relative: Option<ast::Ident>, + dir_path: &Path, + codemap: &CodeMap) -> ModulePath + { + // If we're in a foo.rs file instead of a mod.rs file, + // we need to look for submodules in + // `./foo/<id>.rs` and `./foo/<id>/mod.rs` rather than + // `./<id>.rs` and `./<id>/mod.rs`. + let relative_prefix_string; + let relative_prefix = if let Some(ident) = relative { + relative_prefix_string = format!("{}{}", ident.name.as_str(), path::MAIN_SEPARATOR); + &relative_prefix_string + } else { + "" + }; + let mod_name = id.to_string(); - let default_path_str = format!("{}.rs", mod_name); - let secondary_path_str = format!("{}{}mod.rs", mod_name, path::MAIN_SEPARATOR); + let default_path_str = format!("{}{}.rs", relative_prefix, mod_name); + let secondary_path_str = format!("{}{}{}mod.rs", + relative_prefix, mod_name, path::MAIN_SEPARATOR); let default_path = dir_path.join(&default_path_str); let secondary_path = dir_path.join(&secondary_path_str); let default_exists = codemap.file_exists(&default_path); @@ -5754,12 +5775,16 @@ impl<'a> Parser<'a> { let result = match (default_exists, secondary_exists) { (true, false) => Ok(ModulePathSuccess { path: default_path, - directory_ownership: DirectoryOwnership::UnownedViaMod(false), + directory_ownership: DirectoryOwnership::Owned { + relative: Some(id), + }, warn: false, }), (false, true) => Ok(ModulePathSuccess { path: secondary_path, - directory_ownership: DirectoryOwnership::Owned, + directory_ownership: DirectoryOwnership::Owned { + relative: None, + }, warn: false, }), (false, false) => Err(Error::FileNotFoundForModule { @@ -5790,7 +5815,10 @@ impl<'a> Parser<'a> { if let Some(path) = Parser::submod_path_from_attr(outer_attrs, &self.directory.path) { return Ok(ModulePathSuccess { directory_ownership: match path.file_name().and_then(|s| s.to_str()) { - Some("mod.rs") => DirectoryOwnership::Owned, + Some("mod.rs") => DirectoryOwnership::Owned { relative: None }, + Some(_) => { + DirectoryOwnership::Owned { relative: Some(id) } + } _ => DirectoryOwnership::UnownedViaMod(true), }, path, @@ -5798,49 +5826,69 @@ impl<'a> Parser<'a> { }); } - let paths = Parser::default_submod_path(id, &self.directory.path, self.sess.codemap()); + let relative = match self.directory.ownership { + DirectoryOwnership::Owned { relative } => { + // Push the usage onto the list of non-mod.rs mod uses. + // This is used later for feature-gate error reporting. + if let Some(cur_file_ident) = relative { + self.sess + .non_modrs_mods.borrow_mut() + .push((cur_file_ident, id_sp)); + } + relative + }, + DirectoryOwnership::UnownedViaBlock | + DirectoryOwnership::UnownedViaMod(_) => None, + }; + let paths = Parser::default_submod_path( + id, relative, &self.directory.path, self.sess.codemap()); - if let DirectoryOwnership::UnownedViaBlock = self.directory.ownership { - let msg = - "Cannot declare a non-inline module inside a block unless it has a path attribute"; - let mut err = self.diagnostic().struct_span_err(id_sp, msg); - if paths.path_exists { - let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", - paths.name); - err.span_note(id_sp, &msg); - } - Err(err) - } else if let DirectoryOwnership::UnownedViaMod(warn) = self.directory.ownership { - if warn { - if let Ok(result) = paths.result { - return Ok(ModulePathSuccess { warn: true, ..result }); + match self.directory.ownership { + DirectoryOwnership::Owned { .. } => { + paths.result.map_err(|err| self.span_fatal_err(id_sp, err)) + }, + DirectoryOwnership::UnownedViaBlock => { + let msg = + "Cannot declare a non-inline module inside a block \ + unless it has a path attribute"; + let mut err = self.diagnostic().struct_span_err(id_sp, msg); + if paths.path_exists { + let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", + paths.name); + err.span_note(id_sp, &msg); } + Err(err) } - let mut err = self.diagnostic().struct_span_err(id_sp, - "cannot declare a new module at this location"); - if id_sp != syntax_pos::DUMMY_SP { - let src_path = self.sess.codemap().span_to_filename(id_sp); - if let FileName::Real(src_path) = src_path { - if let Some(stem) = src_path.file_stem() { - let mut dest_path = src_path.clone(); - dest_path.set_file_name(stem); - dest_path.push("mod.rs"); - err.span_note(id_sp, + DirectoryOwnership::UnownedViaMod(warn) => { + if warn { + if let Ok(result) = paths.result { + return Ok(ModulePathSuccess { warn: true, ..result }); + } + } + let mut err = self.diagnostic().struct_span_err(id_sp, + "cannot declare a new module at this location"); + if id_sp != syntax_pos::DUMMY_SP { + let src_path = self.sess.codemap().span_to_filename(id_sp); + if let FileName::Real(src_path) = src_path { + if let Some(stem) = src_path.file_stem() { + let mut dest_path = src_path.clone(); + dest_path.set_file_name(stem); + dest_path.push("mod.rs"); + err.span_note(id_sp, &format!("maybe move this module `{}` to its own \ directory via `{}`", src_path.display(), dest_path.display())); + } } } + if paths.path_exists { + err.span_note(id_sp, + &format!("... or maybe `use` the module `{}` instead \ + of possibly redeclaring it", + paths.name)); + } + Err(err) } - if paths.path_exists { - err.span_note(id_sp, - &format!("... or maybe `use` the module `{}` instead \ - of possibly redeclaring it", - paths.name)); - } - Err(err) - } else { - paths.result.map_err(|err| self.span_fatal_err(id_sp, err)) } } |
