Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 13 additions & 14 deletions crates/sniff-test/src/annotations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
use crate::{
ARGS,
annotations::{doc::get_comment_doc_str, span::Mergeable, toml::TomlAnnotation},
check::LocalError,
properties::Property,
reachability::LocallyReachable,
};
use regex::Regex;
use rustc_hir::{Attribute, def_id::DefId};
use rustc_middle::ty::TyCtxt;
use rustc_span::{ErrorGuaranteed, Span, source_map::Spanned};
use rustc_span::{Span, source_map::Spanned};
use std::{collections::HashMap, fmt::Debug, ops::Range};

mod doc;
Expand Down Expand Up @@ -80,13 +82,14 @@ pub struct ExpressionAnnotation {
}

impl ExpressionAnnotation {
pub fn satisfies_obligation(
pub fn satisfies_obligation<'tcx, P: Property>(
&self,
obligation: &Obligation,
call_to: DefId,
from_span: Span,
tcx: TyCtxt<'_>,
) -> Result<(), ErrorGuaranteed> {
in_fn: &LocallyReachable,
// tcx: TyCtxt<'_>,
) -> Result<(), LocalError<'tcx, P>> {
match obligation {
Obligation::ConsiderProperty => Ok(()),
Obligation::ConsiderConditions(conditions) => {
Expand All @@ -103,16 +106,12 @@ impl ExpressionAnnotation {
.iter()
.map(|a| &a.node.name)
.collect::<Vec<&String>>();
Err(tcx
.dcx()
.struct_span_err(
from_span,
format!(
"call to {:?} w/ text {:?} didn't consider some obligations {:?}",
self.text, call_to, names
),
)
.emit())
Err(LocalError::CallMissedObligations {
func: in_fn.clone(),
callsite_comment: self.text.clone(),
callsite_span: from_span,
obligations: names.into_iter().cloned().collect(),
})
}
}
}
Expand Down
18 changes: 18 additions & 0 deletions crates/sniff-test/src/bin/sniff-test-driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,23 @@

fn main() {
sniff_test::env_logger_init(true);
let args: Vec<String> = std::env::args().collect();
// If there are enough args that we're trying to call the real rustc,
// just pass through to calling the real rustc
if args.len() >= 2 {
let real_rustc = &args[1];
let rest = &args[2..];
let is_passthrough = rest
.iter()
.any(|a| a.starts_with("--print") || a == "-vV" || a == "--version" || a == "-V")
|| rest.is_empty();

if is_passthrough {
use std::os::unix::process::CommandExt;
let err = std::process::Command::new(real_rustc).args(rest).exec();
panic!("failed to exec rustc: {err}");
}
}

rustc_plugin::driver_main(sniff_test::PrintAllItemsPlugin);
}
75 changes: 53 additions & 22 deletions crates/sniff-test/src/check/err.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::properties::FoundAxiom;
use crate::{check::LocalError, properties::FoundAxiom};
use itertools::Itertools;
use rustc_errors::Diag;
use rustc_middle::ty::TyCtxt;
Expand All @@ -11,31 +11,62 @@ use crate::{

pub fn report_errors<'tcx, P: Property>(
tcx: TyCtxt<'tcx>,
func: LocallyReachable,
_property: P,
unjustified_axioms: Vec<FoundAxiom<'tcx, P::Axiom>>,
unjustified_calls: Vec<CallsWObligations>,
errors: Vec<LocalError<'tcx, P>>,
) -> ErrorGuaranteed {
let dcx = tcx.dcx();
let def_span = tcx.def_span(func.reach);
let fn_name = tcx.def_path_str(func.reach.to_def_id());

let mut diag = dcx.struct_span_err(
def_span,
summary::summary_string::<P>(&fn_name, &unjustified_axioms, &unjustified_calls),
);

diag = diag.with_note(reachability_str(&fn_name, tcx, &func));

for axiom in unjustified_axioms {
diag = extend_diag_axiom::<P>(diag, axiom);
}
errors
.into_iter()
.map(|error| report_error(tcx, error))
.last()
.expect("don't call this on empty errors")
}

for calls in unjustified_calls {
diag = extend_diag_calls(diag, tcx, calls);
fn report_error<'tcx, P: Property>(
tcx: TyCtxt<'tcx>,
error: LocalError<'tcx, P>,
) -> ErrorGuaranteed {
let dcx = tcx.dcx();
let def_span = tcx.def_span(error.func().reach);
let fn_name = tcx.def_path_str(error.func().reach.to_def_id());

match error {
LocalError::Basic { tcx, func, _property, unjustified_axioms, unjustified_calls } => {
let mut diag = dcx.struct_span_err(
def_span,
summary::summary_string::<P>(&fn_name, &unjustified_axioms, &unjustified_calls),
);

diag = diag.with_note(reachability_str(&fn_name, tcx, &func));

for axiom in unjustified_axioms {
diag = extend_diag_axiom::<P>(diag, axiom);
}

for calls in unjustified_calls {
diag = extend_diag_calls(diag, tcx, calls);
}

diag.emit()
},
LocalError::CallMissedObligations { callsite_comment: _, callsite_span, obligations, .. } => {
dcx.struct_span_err(
callsite_span,
format!("call to {fn_name} here fails to consider its named obligations {obligations:?}"),
).emit()
},
LocalError::FnDefShouldHaveKeyword { needed_keyword, .. } => {
dcx.struct_span_err(
def_span,
format!("function definition of {fn_name} here should have the {needed_keyword} keyword because of the {} property", P::property_name()),
).emit()
},
LocalError::Trait { inconsistent_w_trait, .. } => {
dcx.struct_span_err(
def_span,
format!("implementation {fn_name} here has {} obligations that are inconsistent with those on the definition of the {} trait", tcx.def_path_debug_str(inconsistent_w_trait), P::property_name()),
).with_span_note(tcx.def_span(inconsistent_w_trait), "which is defined here").emit()
}
}

diag.emit()
}

fn extend_diag_axiom<'tcx, P: Property>(
Expand Down
Loading
Loading