]> git.lizzy.rs Git - rust.git/commitdiff
More perseverant about indeterminate imports.
authorVictor Berger <victor.berger@m4x.org>
Fri, 31 Jul 2015 16:58:59 +0000 (18:58 +0200)
committerVictor Berger <victor.berger@m4x.org>
Fri, 31 Jul 2015 17:10:14 +0000 (19:10 +0200)
Most errors generated by resolve might be caused by
not-yet-resolved glob imports. This changes the behavior of the
resolve imports algorithms to not fail prematurally on first
error, but instead buffer intermediate errors and report them
only when stuck.

Fixes #18083

src/librustc_resolve/lib.rs
src/librustc_resolve/resolve_imports.rs

index f66dfa83ff9489639d62581571a0ae22ed2fcad1..45dbf08071d19fbacfb95a96f82a17901e028263 100644 (file)
@@ -20,6 +20,7 @@
       html_root_url = "http://doc.rust-lang.org/nightly/")]
 
 #![feature(associated_consts)]
+#![feature(borrow_state)]
 #![feature(rc_weak)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
@@ -538,8 +539,8 @@ enum ResolveResult<T> {
 }
 
 impl<T> ResolveResult<T> {
-    fn indeterminate(&self) -> bool {
-        match *self { Indeterminate => true, _ => false }
+    fn success(&self) -> bool {
+        match *self { Success(_) => true, _ => false }
     }
 }
 
@@ -731,7 +732,12 @@ fn new(parent_link: ParentLink,
     }
 
     fn all_imports_resolved(&self) -> bool {
-        self.imports.borrow().len() == self.resolved_import_count.get()
+        if self.imports.borrow_state() == ::std::cell::BorrowState::Writing {
+            // it is currently being resolved ! so nope
+            false
+        } else {
+            self.imports.borrow().len() == self.resolved_import_count.get()
+        }
     }
 }
 
index a9ad0cf137bb901eac9ff9c5156ebe4acd6e8bfb..b368e16d6feac94f28c860eb951bafa7ed84a5fa 100644 (file)
@@ -208,7 +208,7 @@ fn resolve_imports(&mut self) {
                    i, self.resolver.unresolved_imports);
 
             let module_root = self.resolver.graph_root.get_module();
-            self.resolve_imports_for_module_subtree(module_root.clone());
+            let errors = self.resolve_imports_for_module_subtree(module_root.clone());
 
             if self.resolver.unresolved_imports == 0 {
                 debug!("(resolving imports) success");
@@ -216,7 +216,20 @@ fn resolve_imports(&mut self) {
             }
 
             if self.resolver.unresolved_imports == prev_unresolved_imports {
-                self.resolver.report_unresolved_imports(module_root);
+                // resolving failed
+                if errors.len() > 0 {
+                    for (span, path, help) in errors {
+                        resolve_error(self.resolver,
+                                      span,
+                                      ResolutionError::UnresolvedImport(Some((&*path, &*help))));
+                    }
+                } else {
+                    // report unresolved imports only if no hard error was already reported
+                    // to avoid generating multiple errors on the same import
+                    // imports that are still undeterminate at this point are actually blocked
+                    // by errored imports, so there is no point reporting them
+                    self.resolver.report_unresolved_imports(module_root);
+                }
                 break;
             }
 
@@ -227,11 +240,13 @@ fn resolve_imports(&mut self) {
 
     /// Attempts to resolve imports for the given module and all of its
     /// submodules.
-    fn resolve_imports_for_module_subtree(&mut self, module_: Rc<Module>) {
+    fn resolve_imports_for_module_subtree(&mut self, module_: Rc<Module>)
+                                          -> Vec<(Span, String, String)> {
+        let mut errors = Vec::new();
         debug!("(resolving imports for module subtree) resolving {}",
                module_to_string(&*module_));
         let orig_module = replace(&mut self.resolver.current_module, module_.clone());
-        self.resolve_imports_for_module(module_.clone());
+        errors.extend(self.resolve_imports_for_module(module_.clone()));
         self.resolver.current_module = orig_module;
 
         build_reduced_graph::populate_module_if_necessary(self.resolver, &module_);
@@ -241,53 +256,65 @@ fn resolve_imports_for_module_subtree(&mut self, module_: Rc<Module>) {
                     // Nothing to do.
                 }
                 Some(child_module) => {
-                    self.resolve_imports_for_module_subtree(child_module);
+                    errors.extend(self.resolve_imports_for_module_subtree(child_module));
                 }
             }
         }
 
         for (_, child_module) in module_.anonymous_children.borrow().iter() {
-            self.resolve_imports_for_module_subtree(child_module.clone());
+            errors.extend(self.resolve_imports_for_module_subtree(child_module.clone()));
         }
+
+        errors
     }
 
     /// Attempts to resolve imports for the given module only.
-    fn resolve_imports_for_module(&mut self, module: Rc<Module>) {
+    fn resolve_imports_for_module(&mut self, module: Rc<Module>) -> Vec<(Span, String, String)> {
+        let mut errors = Vec::new();
+
         if module.all_imports_resolved() {
             debug!("(resolving imports for module) all imports resolved for \
                    {}",
                    module_to_string(&*module));
-            return;
+            return errors;
         }
 
-        let imports = module.imports.borrow();
+        let mut imports = module.imports.borrow_mut();
         let import_count = imports.len();
-        while module.resolved_import_count.get() < import_count {
+        let mut indeterminate_imports = Vec::new();
+        while module.resolved_import_count.get() + indeterminate_imports.len() < import_count {
             let import_index = module.resolved_import_count.get();
-            let import_directive = &(*imports)[import_index];
             match self.resolve_import_for_module(module.clone(),
-                                                 import_directive) {
+                                                 &imports[import_index]) {
                 ResolveResult::Failed(err) => {
+                    let import_directive = &imports[import_index];
                     let (span, help) = match err {
                         Some((span, msg)) => (span, format!(". {}", msg)),
                         None => (import_directive.span, String::new())
                     };
-                    resolve_error(self.resolver,
-                                    span,
-                                    ResolutionError::UnresolvedImport(
-                                                Some((&*import_path_to_string(
-                                                        &import_directive.module_path,
-                                                        import_directive.subclass),
-                                                      &*help)))
-                                   );
+                    errors.push((span,
+                                 import_path_to_string(
+                                    &import_directive.module_path,
+                                    import_directive.subclass
+                                 ),
+                                 help))
+                }
+                ResolveResult::Indeterminate => {}
+                ResolveResult::Success(()) => {
+                    // count success
+                    module.resolved_import_count
+                          .set(module.resolved_import_count.get() + 1);
+                    continue;
                 }
-                ResolveResult::Indeterminate => break, // Bail out. We'll come around next time.
-                ResolveResult::Success(()) => () // Good. Continue.
             }
+            // This resolution was not successful, keep it for later
+            indeterminate_imports.push(imports.swap_remove(import_index));
 
-            module.resolved_import_count
-                  .set(module.resolved_import_count.get() + 1);
         }
+
+        imports.extend(indeterminate_imports);
+
+        errors
     }
 
     /// Attempts to resolve the given import. The return value indicates
@@ -367,11 +394,10 @@ fn resolve_import_for_module(&mut self,
         }
 
         // Decrement the count of unresolved globs if necessary. But only if
-        // the resolution result is indeterminate -- otherwise we'll stop
-        // processing imports here. (See the loop in
-        // resolve_imports_for_module).
+        // the resolution result is a success -- other cases will
+        // be handled by the main loop.
 
-        if !resolution_result.indeterminate() {
+        if resolution_result.success() {
             match import_directive.subclass {
                 GlobImport => {
                     assert!(module_.glob_count.get() >= 1);