Skip to content

Commit e3c8a71

Browse files
pretty print failing derivation trees
1 parent 2360154 commit e3c8a71

File tree

1 file changed

+48
-153
lines changed

1 file changed

+48
-153
lines changed

compiler-core/src/error.rs

+48-153
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,8 @@ use heck::{ToSnakeCase, ToTitleCase, ToUpperCamelCase};
1414
use hexpm::version::ResolutionError;
1515
use itertools::Itertools;
1616
use pubgrub::package::Package;
17-
use pubgrub::range::Range;
1817
use pubgrub::report::{DerivationTree, Derived, External};
1918
use pubgrub::version::Version;
20-
use std::collections::HashSet;
2119
use std::env;
2220
use std::fmt::{Debug, Display};
2321
use std::io::Write;
@@ -361,8 +359,12 @@ impl Error {
361359

362360
pub fn dependency_resolution_failed(error: ResolutionError) -> Error {
363361
Self::DependencyResolutionFailed(match error {
364-
ResolutionError::NoSolution(derivation_tree) =>
365-
derivation_tree_to_pretty_error_message(derivation_tree),
362+
ResolutionError::NoSolution(mut derivation_tree) => {
363+
derivation_tree.collapse_no_versions();
364+
let derivation_tree = simplify_derivation_tree(derivation_tree);
365+
// TODO)) find a way to use the root package name, here it is hardcoded!
366+
DerivationTreePrinter::new("one".into()).print(&derivation_tree)
367+
}
366368

367369
ResolutionError::ErrorRetrievingDependencies {
368370
package,
@@ -408,164 +410,57 @@ impl Error {
408410
}
409411
}
410412

411-
fn derivation_tree_to_pretty_error_message(
412-
mut derivation_tree: DerivationTree<String, hexpm::version::Version>,
413-
) -> String {
414-
derivation_tree.collapse_no_versions();
415-
let derivation_tree = simplify_derivation_tree(derivation_tree);
416-
417-
pprint_error(0, &derivation_tree);
418-
// TODO))
419-
// This order is not deterministic, so sometimes it will default to the
420-
// original version even though it's almost the same!!
421-
match &derivation_tree {
422-
DerivationTree::Derived(Derived { cause1, cause2, .. }) => {
423-
match (cause1.as_ref(), cause2.as_ref()) {
424-
(
425-
DerivationTree::Derived(Derived { cause1, cause2, .. }),
426-
DerivationTree::External(External::FromDependencyOf(
427-
root,
428-
root_range,
429-
dep,
430-
dep_range_from_root,
431-
)),
432-
) => match (cause1.as_ref(), cause2.as_ref()) {
433-
(
434-
DerivationTree::External(External::FromDependencyOf(
435-
maybe_common,
436-
maybe_common_range,
437-
maybe_dep,
438-
dep_range_from_common,
439-
)),
440-
DerivationTree::External(External::FromDependencyOf(
441-
maybe_root,
442-
maybe_root_range,
443-
common,
444-
common_range,
445-
)),
446-
) if maybe_common == common
447-
&& maybe_common_range == common_range
448-
&& maybe_root == root
449-
&& maybe_root_range == root_range
450-
&& maybe_dep == dep =>
451-
{
452-
// TODO))
453-
// The default look of ranges is confusing and we want to switch
454-
// to one more similar to Gleam's constraints.
455-
// However, at the moment there's no way of doing this:
456-
// https://github.com/pubgrub-rs/pubgrub/issues/258
457-
//
458-
wrap_format!(
459-
"Unable to find compatible versions for the version \
460-
constraints in your gleam.toml:
461-
462-
- `{root}` requires `{common}` to be `{common_range}`
463-
- and all versions of `{common}` in that range require `{dep}` to be `{dep_range_from_common}`
464-
- but `{root}` also requires `{dep}` to be `{dep_range_from_root}`
465-
- and there is no version of `{dep}` that satisfies both constraints
466-
"
467-
)
468-
}
469-
_ => derivation_tree_to_default_error_message(derivation_tree),
470-
},
471-
_ => derivation_tree_to_default_error_message(derivation_tree),
472-
}
473-
}
474-
// In case we can't figure out a good way to display the constraint
475-
// failure then we just use a default error message that just lists the
476-
// conflicting packages; leaving to the user to figure out what went
477-
// wrong.
478-
_ => derivation_tree_to_default_error_message(derivation_tree),
479-
}
413+
struct DerivationTreePrinter<'a> {
414+
previous_subject: Option<&'a String>,
415+
previous_object: Option<&'a String>,
416+
root_package_name: String,
480417
}
481418

482-
fn derivation_tree_to_default_error_message(
483-
derivation_tree: DerivationTree<String, hexpm::version::Version>,
484-
) -> String {
485-
let mut conflicting_packages = HashSet::new();
486-
collect_conflicting_packages(&derivation_tree, &mut conflicting_packages);
419+
impl<'a> DerivationTreePrinter<'a> {
420+
pub fn print(
421+
&mut self,
422+
derivation_tree: &'a DerivationTree<String, hexpm::version::Version>,
423+
) -> String {
424+
match &derivation_tree {
425+
DerivationTree::External(External::FromDependencyOf(
426+
package,
427+
_package_version,
428+
required_package,
429+
required_package_version,
430+
)) => {
431+
let start = if self.previous_subject == Some(package) {
432+
"it also".to_string()
433+
} else if package == &self.root_package_name {
434+
"your package".to_string()
435+
} else if self.previous_object == Some(package) {
436+
format!("and `{package}`")
437+
} else {
438+
format!("`{package}`")
439+
};
487440

488-
wrap_format!(
489-
"Unable to find compatible versions for the version constraints in \
490-
your gleam.toml. The conflicting packages are:
441+
self.previous_subject = Some(package);
442+
self.previous_object = Some(required_package);
491443

492-
{}
493-
",
494-
conflicting_packages
495-
.into_iter()
496-
.map(|s| format!("- {}", s))
497-
.join("\n")
498-
)
499-
}
500-
501-
fn pprint_error<'dt, P: Package, V: Version>(
502-
nest: usize,
503-
derivation_tree: &'dt DerivationTree<P, V>,
504-
) {
505-
match derivation_tree {
506-
DerivationTree::External(external) => match external {
507-
External::NotRoot(_, _) => panic!(),
508-
External::NoVersions(_, _) => panic!(),
509-
External::UnavailableDependencies(_, _) => panic!(),
510-
External::FromDependencyOf(p1, range1, p2, range2) => {
511-
let nesting = " ".repeat(nest);
512-
print!(
513-
"{nesting}FromDepOf {{
514-
{nesting} {p1}: {range1},
515-
{nesting} {p2}: {range2},
516-
{nesting}}}"
444+
format!(
445+
"- {start} requires `{required_package}` to be `{required_package_version}`"
446+
)
447+
}
448+
DerivationTree::External(_) => todo!(),
449+
DerivationTree::Derived(Derived { cause1, cause2, .. }) => {
450+
format!(
451+
"{}\n{}",
452+
self.print(cause2.as_ref()),
453+
self.print(cause1.as_ref()),
517454
)
518455
}
519-
},
520-
521-
DerivationTree::Derived(Derived {
522-
terms: _,
523-
shared_id: _,
524-
cause1,
525-
cause2,
526-
}) => {
527-
let nesting = " ".repeat(nest);
528-
print!(
529-
"{nesting}Derived {{
530-
{nesting} cause1: "
531-
);
532-
pprint_error(nest + 2, cause1.as_ref());
533-
print!(
534-
",
535-
{nesting} cause2: "
536-
);
537-
pprint_error(nest + 2, cause2.as_ref());
538-
print!(
539-
",
540-
{nesting}}}",
541-
)
542456
}
543457
}
544-
}
545458

546-
fn collect_conflicting_packages<'dt, P: Package, V: Version>(
547-
derivation_tree: &'dt DerivationTree<P, V>,
548-
conflicting_packages: &mut HashSet<&'dt P>,
549-
) {
550-
match derivation_tree {
551-
DerivationTree::External(external) => match external {
552-
External::NotRoot(package, _) => {
553-
let _ = conflicting_packages.insert(package);
554-
}
555-
External::NoVersions(package, _) => {
556-
let _ = conflicting_packages.insert(package);
557-
}
558-
External::UnavailableDependencies(package, _) => {
559-
let _ = conflicting_packages.insert(package);
560-
}
561-
External::FromDependencyOf(package, _, dep_package, _) => {
562-
let _ = conflicting_packages.insert(package);
563-
let _ = conflicting_packages.insert(dep_package);
564-
}
565-
},
566-
DerivationTree::Derived(derived) => {
567-
collect_conflicting_packages(&derived.cause1, conflicting_packages);
568-
collect_conflicting_packages(&derived.cause2, conflicting_packages);
459+
fn new(root_package_name: String) -> Self {
460+
Self {
461+
previous_subject: None,
462+
previous_object: None,
463+
root_package_name,
569464
}
570465
}
571466
}

0 commit comments

Comments
 (0)