Skip to content

#48538 Specialization: Intersection Impls #49624

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

Closed
wants to merge 2 commits into from
Closed
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
92 changes: 58 additions & 34 deletions src/librustc/traits/specialize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ pub struct OverlapError {
pub trait_desc: String,
pub self_desc: Option<String>,
pub intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>,
pub used_to_be_allowed: bool,
Copy link
Contributor

Choose a reason for hiding this comment

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

what is this about?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

used_to_be_allowed is the name of a variable currently used in librustc/traits/specialize/mod.rs.
This variable is setted based on the result of the insertion and is linked to the IntercrateMode used to check if two impls overalp.
Since, with my changes, any OverlapErrors is no more emitted at insertion time I keep track of this variable when creating the OverlapError struct and i use it later when checking if two impls overlap.

}

/// Given a subst for the requested impl, translate it to a subst
Expand Down Expand Up @@ -324,56 +325,82 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
def_id.index.as_array_index())
});

let mut overlaps = Vec::new();

for impl_def_id in trait_impls {
if impl_def_id.is_local() {
// This is where impl overlap checking happens:
let insert_result = sg.insert(tcx, impl_def_id);
// Report error if there was one.
let (overlap, used_to_be_allowed) = match insert_result {
Err(overlap) => (Some(overlap), false),
Ok(opt_overlap) => (opt_overlap, true)
match insert_result {
Ok(Some(mut opt_overlaps)) => {
// record any overlap that occurs between two impl
// later those recordings are processed to establish
// if an intersection impl is present between two overlapping impls
// if no an overlap error is emitted
for opt_overlap in opt_overlaps {
overlaps.push((impl_def_id, opt_overlap));
}
}
_ => {}
};
} else {
let parent = tcx.impl_parent(impl_def_id).unwrap_or(trait_id);
sg.record_impl_from_cstore(tcx, parent, impl_def_id)
}
}

if let Some(overlap) = overlap {
let msg = format!("conflicting implementations of trait `{}`{}:{}",
if overlaps.len() > 0 {
// Build the graph only if there is at least an overlap
let (graph, nodes_idx) = sg.build_graph();
for (impl_def_id, overlap) in overlaps {
if !sg.check_overlap(&graph, &nodes_idx, impl_def_id, overlap.with_impl, tcx) {
let msg = format!(
"conflicting implementations of trait `{}`{}:{}",
overlap.trait_desc,
overlap.self_desc.clone().map_or(
String::new(), |ty| {
format!(" for type `{}`", ty)
}),
if used_to_be_allowed { " (E0119)" } else { "" }
);
let impl_span = tcx.sess.codemap().def_span(
tcx.span_of_impl(impl_def_id).unwrap()
overlap
.self_desc
.clone()
.map_or(String::new(), |ty| format!(" for type `{}`", ty)),
if overlap.used_to_be_allowed {
" (E0119)"
} else {
""
}
);
let mut err = if used_to_be_allowed {
let impl_span = tcx.sess
.codemap()
.def_span(tcx.span_of_impl(impl_def_id).unwrap());
let mut err = if overlap.used_to_be_allowed {
tcx.struct_span_lint_node(
lint::builtin::INCOHERENT_FUNDAMENTAL_IMPLS,
tcx.hir.as_local_node_id(impl_def_id).unwrap(),
impl_span,
&msg)
&msg,
)
} else {
struct_span_err!(tcx.sess,
impl_span,
E0119,
"{}",
msg)
struct_span_err!(tcx.sess, impl_span, E0119, "{}", msg)
};

match tcx.span_of_impl(overlap.with_impl) {
Ok(span) => {
err.span_label(tcx.sess.codemap().def_span(span),
format!("first implementation here"));
err.span_label(impl_span,
format!("conflicting implementation{}",
overlap.self_desc
.map_or(String::new(),
|ty| format!(" for `{}`", ty))));
err.span_label(
tcx.sess.codemap().def_span(span),
format!("first implementation here"),
);
err.span_label(
impl_span,
format!(
"conflicting implementation{}",
overlap
.self_desc
.map_or(String::new(), |ty| format!(" for `{}`", ty))
),
);
}
Err(cname) => {
let msg = match to_pretty_impl_header(tcx, overlap.with_impl) {
Some(s) => format!(
"conflicting implementation in crate `{}`:\n- {}", cname, s),
Some(s) => {
format!("conflicting implementation in crate `{}`:\n- {}", cname, s)
}
None => format!("conflicting implementation in crate `{}`", cname),
};
err.note(&msg);
Expand All @@ -386,9 +413,6 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx

err.emit();
}
} else {
let parent = tcx.impl_parent(impl_def_id).unwrap_or(trait_id);
sg.record_impl_from_cstore(tcx, parent, impl_def_id)
}
}

Expand Down
Loading