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

Elide object safety errors on non-existent trait function #58929

Merged
merged 1 commit into from
Mar 23, 2019
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
4 changes: 4 additions & 0 deletions src/librustc/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,9 @@ pub struct Session {

/// Cap lint level specified by a driver specifically.
pub driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,

/// `Span`s of trait methods that weren't found to avoid emitting object safety errors
pub trait_methods_not_found: OneThread<RefCell<FxHashSet<Span>>>,
Copy link
Contributor

Choose a reason for hiding this comment

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

This is potentially used on multiple threads.

}

pub struct PerfStats {
Expand Down Expand Up @@ -1230,6 +1233,7 @@ fn build_session_(
has_global_allocator: Once::new(),
has_panic_handler: Once::new(),
driver_lint_caps,
trait_methods_not_found: OneThread::new(RefCell::new(Default::default())),
};

validate_commandline_args_with_session_available(&sess);
Expand Down
36 changes: 25 additions & 11 deletions src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -754,9 +754,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
ty::Predicate::ObjectSafe(trait_def_id) => {
let violations = self.tcx.global_tcx()
.object_safety_violations(trait_def_id);
self.tcx.report_object_safety_error(span,
trait_def_id,
violations)
if let Some(err) = self.tcx.report_object_safety_error(
span,
trait_def_id,
violations,
) {
err
} else {
return;
}
}

ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
Expand Down Expand Up @@ -884,7 +890,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {

TraitNotObjectSafe(did) => {
let violations = self.tcx.global_tcx().object_safety_violations(did);
self.tcx.report_object_safety_error(span, did, violations)
if let Some(err) = self.tcx.report_object_safety_error(span, did, violations) {
err
} else {
return;
}
}

// already reported in the query
Expand Down Expand Up @@ -1293,12 +1303,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
err
}

pub fn report_object_safety_error(self,
span: Span,
trait_def_id: DefId,
violations: Vec<ObjectSafetyViolation>)
-> DiagnosticBuilder<'tcx>
{
pub fn report_object_safety_error(
self,
span: Span,
trait_def_id: DefId,
violations: Vec<ObjectSafetyViolation>,
) -> Option<DiagnosticBuilder<'tcx>> {
if self.sess.trait_methods_not_found.borrow().contains(&span) {
// Avoid emitting error caused by non-existing method (#58734)
return None;
}
let trait_str = self.def_path_str(trait_def_id);
let span = self.sess.source_map().def_span(span);
let mut err = struct_span_err!(
Expand All @@ -1313,7 +1327,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
err.note(&violation.error_msg());
}
}
err
Some(err)
}
}

Expand Down
5 changes: 2 additions & 3 deletions src/librustc_typeck/astconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1012,9 +1012,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
let object_safety_violations =
tcx.global_tcx().astconv_object_safety_violations(principal.def_id());
if !object_safety_violations.is_empty() {
tcx.report_object_safety_error(
span, principal.def_id(), object_safety_violations)
.emit();
tcx.report_object_safety_error(span, principal.def_id(), object_safety_violations)
.map(|mut err| err.emit());
return tcx.types.err;
}

Expand Down
17 changes: 10 additions & 7 deletions src/librustc_typeck/check/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
}

pub fn report_method_error<'b>(&self,
span: Span,
rcvr_ty: Ty<'tcx>,
item_name: ast::Ident,
source: SelfSource<'b>,
error: MethodError<'tcx>,
args: Option<&'gcx [hir::Expr]>) {
pub fn report_method_error<'b>(
&self,
span: Span,
rcvr_ty: Ty<'tcx>,
item_name: ast::Ident,
source: SelfSource<'b>,
error: MethodError<'tcx>,
args: Option<&'gcx [hir::Expr]>,
) {
// Avoid suggestions when we don't know what's going on.
if rcvr_ty.references_error() {
return;
Expand Down Expand Up @@ -373,6 +375,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
} else {
err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
self.tcx.sess.trait_methods_not_found.borrow_mut().insert(span);
}

if self.is_fn_ty(&rcvr_ty, span) {
Expand Down
22 changes: 22 additions & 0 deletions src/test/ui/issues/issue-58734.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
trait Trait {
fn exists(self) -> ();

fn not_object_safe() -> Self;
}

impl Trait for () {
fn exists(self) -> () {
}

fn not_object_safe() -> Self {
()
}
}

fn main() {
// object-safe or not, this call is OK
Trait::exists(());
// no object safety error
Trait::nonexistent(());
//~^ ERROR no function or associated item named `nonexistent` found for type `dyn Trait`
}
11 changes: 11 additions & 0 deletions src/test/ui/issues/issue-58734.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0599]: no function or associated item named `nonexistent` found for type `dyn Trait` in the current scope
--> $DIR/issue-58734.rs:20:12
|
LL | Trait::nonexistent(());
| -------^^^^^^^^^^^
| |
| function or associated item not found in `dyn Trait`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0599`.