Skip to content

Commit 1a019dc

Browse files
committed
Auto merge of #31925 - aturon:inherent-overlap, r=nikomatsakis
Forbid items with the same name from appearing in overlapping inherent impl blocks For example, the following is now correctly illegal: ```rust struct Foo; impl Foo { fn id() {} } impl Foo { fn id() {} } ``` "Overlapping" here is determined the same way it is for traits (and in fact shares the same code path): roughly, there must be some way of substituting any generic types to unify the impls, such that none of the `where` clauses are provably unsatisfiable under such a unification. Along the way, this PR also introduces an `ImplHeader` abstraction (the first commit) that makes it easier to work with impls abstractly (without caring whether they are trait or inherent impl blocks); see the first commit. Closes #22889 r? @nikomatsakis
2 parents f1d6f12 + 6265b6b commit 1a019dc

20 files changed

+253
-109
lines changed

src/librustc/dep_graph/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ pub enum DepNode {
5858
CoherenceCheckImpl(DefId),
5959
CoherenceOverlapCheck(DefId),
6060
CoherenceOverlapCheckSpecial(DefId),
61+
CoherenceOverlapInherentCheck(DefId),
6162
CoherenceOrphanCheck(DefId),
6263
Variance,
6364
WfCheck(DefId),

src/librustc/middle/infer/mod.rs

+22-9
Original file line numberDiff line numberDiff line change
@@ -458,14 +458,13 @@ pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
458458
}
459459

460460
pub fn mk_eq_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
461-
a_is_expected: bool,
462-
origin: TypeOrigin,
463-
a: ty::TraitRef<'tcx>,
464-
b: ty::TraitRef<'tcx>)
465-
-> UnitResult<'tcx>
461+
a_is_expected: bool,
462+
origin: TypeOrigin,
463+
a: ty::TraitRef<'tcx>,
464+
b: ty::TraitRef<'tcx>)
465+
-> UnitResult<'tcx>
466466
{
467-
debug!("mk_eq_trait_refs({:?} <: {:?})",
468-
a, b);
467+
debug!("mk_eq_trait_refs({:?} = {:?})", a, b);
469468
cx.eq_trait_refs(a_is_expected, origin, a, b)
470469
}
471470

@@ -476,11 +475,25 @@ pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
476475
b: ty::PolyTraitRef<'tcx>)
477476
-> UnitResult<'tcx>
478477
{
479-
debug!("mk_sub_poly_trait_refs({:?} <: {:?})",
480-
a, b);
478+
debug!("mk_sub_poly_trait_refs({:?} <: {:?})", a, b);
481479
cx.sub_poly_trait_refs(a_is_expected, origin, a, b)
482480
}
483481

482+
pub fn mk_eq_impl_headers<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
483+
a_is_expected: bool,
484+
origin: TypeOrigin,
485+
a: &ty::ImplHeader<'tcx>,
486+
b: &ty::ImplHeader<'tcx>)
487+
-> UnitResult<'tcx>
488+
{
489+
debug!("mk_eq_impl_header({:?} = {:?})", a, b);
490+
match (a.trait_ref, b.trait_ref) {
491+
(Some(a_ref), Some(b_ref)) => mk_eq_trait_refs(cx, a_is_expected, origin, a_ref, b_ref),
492+
(None, None) => mk_eqty(cx, a_is_expected, origin, a.self_ty, b.self_ty),
493+
_ => cx.tcx.sess.bug("mk_eq_impl_headers given mismatched impl kinds"),
494+
}
495+
}
496+
484497
fn expected_found<T>(a_is_expected: bool,
485498
a: T,
486499
b: T)

src/librustc/middle/traits/coherence.rs

+25-69
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,25 @@
1010

1111
//! See `README.md` for high-level documentation
1212
13-
use super::Normalized;
14-
use super::SelectionContext;
15-
use super::ObligationCause;
16-
use super::PredicateObligation;
17-
use super::project;
18-
use super::util;
13+
use super::{SelectionContext};
14+
use super::{Obligation, ObligationCause};
1915

2016
use middle::cstore::LOCAL_CRATE;
2117
use middle::def_id::DefId;
22-
use middle::subst::{Subst, Substs, TypeSpace};
18+
use middle::subst::TypeSpace;
2319
use middle::ty::{self, Ty, TyCtxt};
2420
use middle::infer::{self, InferCtxt, TypeOrigin};
25-
use syntax::codemap::{DUMMY_SP, Span};
21+
use syntax::codemap::DUMMY_SP;
2622

2723
#[derive(Copy, Clone)]
2824
struct InferIsLocal(bool);
2925

30-
/// If there are types that satisfy both impls, returns a `TraitRef`
26+
/// If there are types that satisfy both impls, returns an `ImplTy`
3127
/// with those types substituted (by updating the given `infcx`)
3228
pub fn overlapping_impls<'cx, 'tcx>(infcx: &InferCtxt<'cx, 'tcx>,
3329
impl1_def_id: DefId,
3430
impl2_def_id: DefId)
35-
-> Option<ty::TraitRef<'tcx>>
31+
-> Option<ty::ImplHeader<'tcx>>
3632
{
3733
debug!("impl_can_satisfy(\
3834
impl1_def_id={:?}, \
@@ -45,34 +41,28 @@ pub fn overlapping_impls<'cx, 'tcx>(infcx: &InferCtxt<'cx, 'tcx>,
4541
}
4642

4743
/// Can both impl `a` and impl `b` be satisfied by a common type (including
48-
/// `where` clauses)? If so, returns a `TraitRef` that unifies the two impls.
44+
/// `where` clauses)? If so, returns an `ImplHeader` that unifies the two impls.
4945
fn overlap<'cx, 'tcx>(selcx: &mut SelectionContext<'cx, 'tcx>,
5046
a_def_id: DefId,
5147
b_def_id: DefId)
52-
-> Option<ty::TraitRef<'tcx>>
48+
-> Option<ty::ImplHeader<'tcx>>
5349
{
5450
debug!("overlap(a_def_id={:?}, b_def_id={:?})",
5551
a_def_id,
5652
b_def_id);
5753

58-
let (a_trait_ref, a_obligations) = impl_trait_ref_and_oblig(selcx,
59-
a_def_id,
60-
util::fresh_type_vars_for_impl);
54+
let a_impl_header = ty::ImplHeader::with_fresh_ty_vars(selcx, a_def_id);
55+
let b_impl_header = ty::ImplHeader::with_fresh_ty_vars(selcx, b_def_id);
6156

62-
let (b_trait_ref, b_obligations) = impl_trait_ref_and_oblig(selcx,
63-
b_def_id,
64-
util::fresh_type_vars_for_impl);
65-
66-
debug!("overlap: a_trait_ref={:?} a_obligations={:?}", a_trait_ref, a_obligations);
67-
68-
debug!("overlap: b_trait_ref={:?} b_obligations={:?}", b_trait_ref, b_obligations);
57+
debug!("overlap: a_impl_header={:?}", a_impl_header);
58+
debug!("overlap: b_impl_header={:?}", b_impl_header);
6959

7060
// Do `a` and `b` unify? If not, no overlap.
71-
if let Err(_) = infer::mk_eq_trait_refs(selcx.infcx(),
72-
true,
73-
TypeOrigin::Misc(DUMMY_SP),
74-
a_trait_ref,
75-
b_trait_ref) {
61+
if let Err(_) = infer::mk_eq_impl_headers(selcx.infcx(),
62+
true,
63+
TypeOrigin::Misc(DUMMY_SP),
64+
&a_impl_header,
65+
&b_impl_header) {
7666
return None;
7767
}
7868

@@ -81,17 +71,21 @@ fn overlap<'cx, 'tcx>(selcx: &mut SelectionContext<'cx, 'tcx>,
8171
// Are any of the obligations unsatisfiable? If so, no overlap.
8272
let infcx = selcx.infcx();
8373
let opt_failing_obligation =
84-
a_obligations.iter()
85-
.chain(&b_obligations)
86-
.map(|o| infcx.resolve_type_vars_if_possible(o))
74+
a_impl_header.predicates
75+
.iter()
76+
.chain(&b_impl_header.predicates)
77+
.map(|p| infcx.resolve_type_vars_if_possible(p))
78+
.map(|p| Obligation { cause: ObligationCause::dummy(),
79+
recursion_depth: 0,
80+
predicate: p })
8781
.find(|o| !selcx.evaluate_obligation(o));
8882

8983
if let Some(failing_obligation) = opt_failing_obligation {
9084
debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
9185
return None
9286
}
9387

94-
Some(selcx.infcx().resolve_type_vars_if_possible(&a_trait_ref))
88+
Some(selcx.infcx().resolve_type_vars_if_possible(&a_impl_header))
9589
}
9690

9791
pub fn trait_ref_is_knowable<'tcx>(tcx: &TyCtxt<'tcx>, trait_ref: &ty::TraitRef<'tcx>) -> bool
@@ -125,44 +119,6 @@ pub fn trait_ref_is_knowable<'tcx>(tcx: &TyCtxt<'tcx>, trait_ref: &ty::TraitRef<
125119
orphan_check_trait_ref(tcx, trait_ref, InferIsLocal(true)).is_err()
126120
}
127121

128-
type SubstsFn = for<'a,'tcx> fn(infcx: &InferCtxt<'a, 'tcx>,
129-
span: Span,
130-
impl_def_id: DefId)
131-
-> Substs<'tcx>;
132-
133-
/// Instantiate fresh variables for all bound parameters of the impl
134-
/// and return the impl trait ref with those variables substituted.
135-
fn impl_trait_ref_and_oblig<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
136-
impl_def_id: DefId,
137-
substs_fn: SubstsFn)
138-
-> (ty::TraitRef<'tcx>,
139-
Vec<PredicateObligation<'tcx>>)
140-
{
141-
let impl_substs =
142-
&substs_fn(selcx.infcx(), DUMMY_SP, impl_def_id);
143-
let impl_trait_ref =
144-
selcx.tcx().impl_trait_ref(impl_def_id).unwrap();
145-
let impl_trait_ref =
146-
impl_trait_ref.subst(selcx.tcx(), impl_substs);
147-
let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } =
148-
project::normalize(selcx, ObligationCause::dummy(), &impl_trait_ref);
149-
150-
let predicates = selcx.tcx().lookup_predicates(impl_def_id);
151-
let predicates = predicates.instantiate(selcx.tcx(), impl_substs);
152-
let Normalized { value: predicates, obligations: normalization_obligations2 } =
153-
project::normalize(selcx, ObligationCause::dummy(), &predicates);
154-
let impl_obligations =
155-
util::predicates_for_generics(ObligationCause::dummy(), 0, &predicates);
156-
157-
let impl_obligations: Vec<_> =
158-
impl_obligations.into_iter()
159-
.chain(normalization_obligations1)
160-
.chain(normalization_obligations2)
161-
.collect();
162-
163-
(impl_trait_ref, impl_obligations)
164-
}
165-
166122
pub enum OrphanCheckErr<'tcx> {
167123
NoLocalInputType,
168124
UncoveredTy(Ty<'tcx>),

src/librustc/middle/traits/select.rs

-1
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
391391
// The result is "true" if the obligation *may* hold and "false" if
392392
// we can be sure it does not.
393393

394-
395394
/// Evaluates whether the obligation `obligation` can be satisfied (by any means).
396395
pub fn evaluate_obligation(&mut self,
397396
obligation: &PredicateObligation<'tcx>)

src/librustc/middle/ty/fold.rs

+4
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,10 @@ pub trait TypeFolder<'tcx> : Sized {
146146
t.super_fold_with(self)
147147
}
148148

149+
fn fold_impl_header(&mut self, imp: &ty::ImplHeader<'tcx>) -> ty::ImplHeader<'tcx> {
150+
imp.super_fold_with(self)
151+
}
152+
149153
fn fold_substs(&mut self,
150154
substs: &subst::Substs<'tcx>)
151155
-> subst::Substs<'tcx> {

src/librustc/middle/ty/mod.rs

+35
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,41 @@ impl ImplOrTraitItemContainer {
152152
}
153153
}
154154

155+
/// The "header" of an impl is everything outside the body: a Self type, a trait
156+
/// ref (in the case of a trait impl), and a set of predicates (from the
157+
/// bounds/where clauses).
158+
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
159+
pub struct ImplHeader<'tcx> {
160+
pub impl_def_id: DefId,
161+
pub self_ty: Ty<'tcx>,
162+
pub trait_ref: Option<TraitRef<'tcx>>,
163+
pub predicates: Vec<Predicate<'tcx>>,
164+
}
165+
166+
impl<'tcx> ImplHeader<'tcx> {
167+
pub fn with_fresh_ty_vars<'a>(selcx: &mut traits::SelectionContext<'a, 'tcx>,
168+
impl_def_id: DefId)
169+
-> ImplHeader<'tcx>
170+
{
171+
let tcx = selcx.tcx();
172+
let impl_generics = tcx.lookup_item_type(impl_def_id).generics;
173+
let impl_substs = selcx.infcx().fresh_substs_for_generics(DUMMY_SP, &impl_generics);
174+
175+
let header = ImplHeader {
176+
impl_def_id: impl_def_id,
177+
self_ty: tcx.lookup_item_type(impl_def_id).ty,
178+
trait_ref: tcx.impl_trait_ref(impl_def_id),
179+
predicates: tcx.lookup_predicates(impl_def_id).predicates.into_vec(),
180+
}.subst(tcx, &impl_substs);
181+
182+
let traits::Normalized { value: mut header, obligations } =
183+
traits::normalize(selcx, traits::ObligationCause::dummy(), &header);
184+
185+
header.predicates.extend(obligations.into_iter().map(|o| o.predicate));
186+
header
187+
}
188+
}
189+
155190
#[derive(Clone)]
156191
pub enum ImplOrTraitItem<'tcx> {
157192
ConstTraitItem(Rc<AssociatedConst<'tcx>>),

src/librustc/middle/ty/structural_impls.rs

+21
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,27 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TraitRef<'tcx> {
446446
}
447447
}
448448

449+
impl<'tcx> TypeFoldable<'tcx> for ty::ImplHeader<'tcx> {
450+
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
451+
ty::ImplHeader {
452+
impl_def_id: self.impl_def_id,
453+
self_ty: self.self_ty.fold_with(folder),
454+
trait_ref: self.trait_ref.map(|t| t.fold_with(folder)),
455+
predicates: self.predicates.iter().map(|p| p.fold_with(folder)).collect(),
456+
}
457+
}
458+
459+
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
460+
folder.fold_impl_header(self)
461+
}
462+
463+
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
464+
self.self_ty.visit_with(visitor) ||
465+
self.trait_ref.map(|r| r.visit_with(visitor)).unwrap_or(false) ||
466+
self.predicates.iter().any(|p| p.visit_with(visitor))
467+
}
468+
}
469+
449470
impl<'tcx> TypeFoldable<'tcx> for ty::Region {
450471
fn super_fold_with<F: TypeFolder<'tcx>>(&self, _folder: &mut F) -> Self {
451472
*self

src/librustc_typeck/coherence/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ use CrateCtxt;
3535
use middle::infer::{self, InferCtxt, TypeOrigin, new_infer_ctxt};
3636
use std::cell::RefCell;
3737
use std::rc::Rc;
38+
use syntax::ast;
3839
use syntax::codemap::Span;
40+
use syntax::errors::DiagnosticBuilder;
3941
use util::nodemap::{DefIdMap, FnvHashMap};
4042
use rustc::dep_graph::DepNode;
4143
use rustc::front::map as hir_map;
@@ -519,6 +521,13 @@ fn enforce_trait_manually_implementable(tcx: &TyCtxt, sp: Span, trait_def_id: De
519521
err.emit();
520522
}
521523

524+
// Factored out into helper because the error cannot be defined in multiple locations.
525+
pub fn report_duplicate_item<'tcx>(tcx: &TyCtxt<'tcx>, sp: Span, name: ast::Name)
526+
-> DiagnosticBuilder<'tcx>
527+
{
528+
struct_span_err!(tcx.sess, sp, E0201, "duplicate definitions with name `{}`:", name)
529+
}
530+
522531
pub fn check_coherence(crate_context: &CrateCtxt) {
523532
let _task = crate_context.tcx.dep_graph.in_task(DepNode::Coherence);
524533
let infcx = new_infer_ctxt(crate_context.tcx, &crate_context.tcx.tables, None);

0 commit comments

Comments
 (0)