Skip to content

Commit 03d3ba7

Browse files
committed
Implement the changes to coherence such that we consider a type to be
local only if matches `FUNDAMENTAL(LocalType)`, where `FUNDAMENTAL` includes `&T` and types marked as fundamental (which includes `Box`). Also apply these tests to negative reasoning.
1 parent 8943653 commit 03d3ba7

File tree

7 files changed

+337
-165
lines changed

7 files changed

+337
-165
lines changed

src/librustc/middle/traits/coherence.rs

Lines changed: 150 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,17 @@ use super::PredicateObligation;
1717
use super::project;
1818
use super::util;
1919

20-
use middle::subst::{Subst, TypeSpace};
20+
use middle::subst::{Subst, Substs, TypeSpace};
2121
use middle::ty::{self, ToPolyTraitRef, Ty};
2222
use middle::infer::{self, InferCtxt};
23-
use std::collections::HashSet;
2423
use std::rc::Rc;
2524
use syntax::ast;
26-
use syntax::codemap::DUMMY_SP;
25+
use syntax::codemap::{DUMMY_SP, Span};
2726
use util::ppaux::Repr;
2827

28+
#[derive(Copy)]
29+
struct ParamIsLocal(bool);
30+
2931
/// True if there exist types that satisfy both of the two given impls.
3032
pub fn overlapping_impls(infcx: &InferCtxt,
3133
impl1_def_id: ast::DefId,
@@ -56,10 +58,16 @@ fn overlap(selcx: &mut SelectionContext,
5658
a_def_id.repr(selcx.tcx()),
5759
b_def_id.repr(selcx.tcx()));
5860

59-
let (a_trait_ref, a_obligations) = impl_trait_ref_and_oblig(selcx, a_def_id);
60-
let (b_trait_ref, b_obligations) = impl_trait_ref_and_oblig(selcx, b_def_id);
61+
let (a_trait_ref, a_obligations) = impl_trait_ref_and_oblig(selcx,
62+
a_def_id,
63+
util::free_substs_for_impl);
64+
65+
let (b_trait_ref, b_obligations) = impl_trait_ref_and_oblig(selcx,
66+
b_def_id,
67+
util::fresh_type_vars_for_impl);
6168

6269
debug!("overlap: a_trait_ref={}", a_trait_ref.repr(selcx.tcx()));
70+
6371
debug!("overlap: b_trait_ref={}", b_trait_ref.repr(selcx.tcx()));
6472

6573
// Does `a <: b` hold? If not, no overlap.
@@ -74,28 +82,68 @@ fn overlap(selcx: &mut SelectionContext,
7482
debug!("overlap: subtraitref check succeeded");
7583

7684
// Are any of the obligations unsatisfiable? If so, no overlap.
85+
let tcx = selcx.tcx();
86+
let infcx = selcx.infcx();
7787
let opt_failing_obligation =
7888
a_obligations.iter()
7989
.chain(b_obligations.iter())
90+
.map(|o| infcx.resolve_type_vars_if_possible(o))
8091
.find(|o| !selcx.evaluate_obligation(o));
8192

8293
if let Some(failing_obligation) = opt_failing_obligation {
83-
debug!("overlap: obligation unsatisfiable {}", failing_obligation.repr(selcx.tcx()));
84-
return false;
94+
debug!("overlap: obligation unsatisfiable {}", failing_obligation.repr(tcx));
95+
return false
8596
}
8697

8798
true
8899
}
89100

101+
pub fn trait_ref_is_knowable<'tcx>(tcx: &ty::ctxt<'tcx>, trait_ref: &ty::TraitRef<'tcx>) -> bool
102+
{
103+
debug!("trait_ref_is_knowable(trait_ref={})", trait_ref.repr(tcx));
104+
105+
// if the orphan rules pass, that means that no ancestor crate can
106+
// impl this, so it's up to us.
107+
if orphan_check_trait_ref(tcx, trait_ref, ParamIsLocal(false)).is_ok() {
108+
debug!("trait_ref_is_knowable: orphan check passed");
109+
return true;
110+
}
111+
112+
// if the trait is not marked fundamental, then it's always possible that
113+
// an ancestor crate will impl this in the future, if they haven't
114+
// already
115+
if
116+
trait_ref.def_id.krate != ast::LOCAL_CRATE &&
117+
!ty::has_attr(tcx, trait_ref.def_id, "fundamental")
118+
{
119+
debug!("trait_ref_is_knowable: trait is neither local nor fundamental");
120+
return false;
121+
}
122+
123+
// find out when some downstream (or cousin) crate could impl this
124+
// trait-ref, presuming that all the parameters were instantiated
125+
// with downstream types. If not, then it could only be
126+
// implemented by an upstream crate, which means that the impl
127+
// must be visible to us, and -- since the trait is fundamental
128+
// -- we can test.
129+
orphan_check_trait_ref(tcx, trait_ref, ParamIsLocal(true)).is_err()
130+
}
131+
132+
type SubstsFn = for<'a,'tcx> fn(infcx: &InferCtxt<'a, 'tcx>,
133+
span: Span,
134+
impl_def_id: ast::DefId)
135+
-> Substs<'tcx>;
136+
90137
/// Instantiate fresh variables for all bound parameters of the impl
91138
/// and return the impl trait ref with those variables substituted.
92139
fn impl_trait_ref_and_oblig<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
93-
impl_def_id: ast::DefId)
140+
impl_def_id: ast::DefId,
141+
substs_fn: SubstsFn)
94142
-> (Rc<ty::TraitRef<'tcx>>,
95143
Vec<PredicateObligation<'tcx>>)
96144
{
97145
let impl_substs =
98-
&util::fresh_substs_for_impl(selcx.infcx(), DUMMY_SP, impl_def_id);
146+
&substs_fn(selcx.infcx(), DUMMY_SP, impl_def_id);
99147
let impl_trait_ref =
100148
ty::impl_trait_ref(selcx.tcx(), impl_def_id).unwrap();
101149
let impl_trait_ref =
@@ -134,12 +182,12 @@ pub fn orphan_check<'tcx>(tcx: &ty::ctxt<'tcx>,
134182
impl_def_id: ast::DefId)
135183
-> Result<(), OrphanCheckErr<'tcx>>
136184
{
137-
debug!("impl_is_local({})", impl_def_id.repr(tcx));
185+
debug!("orphan_check({})", impl_def_id.repr(tcx));
138186

139187
// We only except this routine to be invoked on implementations
140188
// of a trait, not inherent implementations.
141189
let trait_ref = ty::impl_trait_ref(tcx, impl_def_id).unwrap();
142-
debug!("trait_ref={}", trait_ref.repr(tcx));
190+
debug!("orphan_check: trait_ref={}", trait_ref.repr(tcx));
143191

144192
// If the *trait* is local to the crate, ok.
145193
if trait_ref.def_id.krate == ast::LOCAL_CRATE {
@@ -148,34 +196,106 @@ pub fn orphan_check<'tcx>(tcx: &ty::ctxt<'tcx>,
148196
return Ok(());
149197
}
150198

199+
orphan_check_trait_ref(tcx, &trait_ref, ParamIsLocal(false))
200+
}
201+
202+
fn orphan_check_trait_ref<'tcx>(tcx: &ty::ctxt<'tcx>,
203+
trait_ref: &ty::TraitRef<'tcx>,
204+
param_is_local: ParamIsLocal)
205+
-> Result<(), OrphanCheckErr<'tcx>>
206+
{
207+
debug!("orphan_check_trait_ref(trait_ref={}, param_is_local={})",
208+
trait_ref.repr(tcx), param_is_local.0);
209+
151210
// First, create an ordered iterator over all the type parameters to the trait, with the self
152211
// type appearing first.
153212
let input_tys = Some(trait_ref.self_ty());
154213
let input_tys = input_tys.iter().chain(trait_ref.substs.types.get_slice(TypeSpace).iter());
155-
let mut input_tys = input_tys;
156214

157215
// Find the first input type that either references a type parameter OR
158216
// some local type.
159-
match input_tys.find(|&&input_ty| references_local_or_type_parameter(tcx, input_ty)) {
160-
Some(&input_ty) => {
161-
// Within this first type, check that all type parameters are covered by a local
162-
// type constructor. Note that if there is no local type constructor, then any
163-
// type parameter at all will be an error.
164-
let covered_params = type_parameters_covered_by_ty(tcx, input_ty);
165-
let all_params = type_parameters_reachable_from_ty(input_ty);
166-
for &param in all_params.difference(&covered_params) {
167-
return Err(OrphanCheckErr::UncoveredTy(param));
217+
for input_ty in input_tys {
218+
if ty_is_local(tcx, input_ty, param_is_local) {
219+
debug!("orphan_check_trait_ref: ty_is_local `{}`", input_ty.repr(tcx));
220+
221+
// First local input type. Check that there are no
222+
// uncovered type parameters.
223+
let uncovered_tys = uncovered_tys(tcx, input_ty, param_is_local);
224+
for uncovered_ty in uncovered_tys {
225+
if let Some(param) = uncovered_ty.walk().find(|t| is_type_parameter(t)) {
226+
debug!("orphan_check_trait_ref: uncovered type `{}`", param.repr(tcx));
227+
return Err(OrphanCheckErr::UncoveredTy(param));
228+
}
168229
}
230+
231+
// OK, found local type, all prior types upheld invariant.
232+
return Ok(());
169233
}
170-
None => {
171-
return Err(OrphanCheckErr::NoLocalInputType);
234+
235+
// Otherwise, enforce invariant that there are no type
236+
// parameters reachable.
237+
if !param_is_local.0 {
238+
if let Some(param) = input_ty.walk().find(|t| is_type_parameter(t)) {
239+
debug!("orphan_check_trait_ref: uncovered type `{}`", param.repr(tcx));
240+
return Err(OrphanCheckErr::UncoveredTy(param));
241+
}
172242
}
173243
}
174244

175-
return Ok(());
245+
// If we exit above loop, never found a local type.
246+
debug!("orphan_check_trait_ref: no local type");
247+
return Err(OrphanCheckErr::NoLocalInputType);
248+
}
249+
250+
fn uncovered_tys<'tcx>(tcx: &ty::ctxt<'tcx>,
251+
ty: Ty<'tcx>,
252+
param_is_local: ParamIsLocal)
253+
-> Vec<Ty<'tcx>>
254+
{
255+
if ty_is_local_constructor(tcx, ty, param_is_local) {
256+
vec![]
257+
} else if fundamental_ty(tcx, ty) {
258+
ty.walk_shallow()
259+
.flat_map(|t| uncovered_tys(tcx, t, param_is_local).into_iter())
260+
.collect()
261+
} else {
262+
vec![ty]
263+
}
176264
}
177265

178-
fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
266+
fn is_type_parameter<'tcx>(ty: Ty<'tcx>) -> bool {
267+
match ty.sty {
268+
// FIXME(#20590) straighten story about projection types
269+
ty::ty_projection(..) | ty::ty_param(..) => true,
270+
_ => false,
271+
}
272+
}
273+
274+
fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>, param_is_local: ParamIsLocal) -> bool
275+
{
276+
ty_is_local_constructor(tcx, ty, param_is_local) ||
277+
fundamental_ty(tcx, ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, param_is_local))
278+
}
279+
280+
fn fundamental_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool
281+
{
282+
match ty.sty {
283+
ty::ty_uniq(..) | ty::ty_rptr(..) =>
284+
true,
285+
ty::ty_enum(def_id, _) | ty::ty_struct(def_id, _) =>
286+
ty::has_attr(tcx, def_id, "fundamental"),
287+
ty::ty_trait(ref data) =>
288+
ty::has_attr(tcx, data.principal_def_id(), "fundamental"),
289+
_ =>
290+
false
291+
}
292+
}
293+
294+
fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>,
295+
ty: Ty<'tcx>,
296+
param_is_local: ParamIsLocal)
297+
-> bool
298+
{
179299
debug!("ty_is_local_constructor({})", ty.repr(tcx));
180300

181301
match ty.sty {
@@ -190,11 +310,15 @@ fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
190310
ty::ty_ptr(..) |
191311
ty::ty_rptr(..) |
192312
ty::ty_tup(..) |
193-
ty::ty_param(..) |
313+
ty::ty_infer(..) |
194314
ty::ty_projection(..) => {
195315
false
196316
}
197317

318+
ty::ty_param(..) => {
319+
param_is_local.0
320+
}
321+
198322
ty::ty_enum(def_id, _) |
199323
ty::ty_struct(def_id, _) => {
200324
def_id.krate == ast::LOCAL_CRATE
@@ -210,7 +334,6 @@ fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
210334
}
211335

212336
ty::ty_closure(..) |
213-
ty::ty_infer(..) |
214337
ty::ty_err => {
215338
tcx.sess.bug(
216339
&format!("ty_is_local invoked on unexpected type: {}",
@@ -219,30 +342,4 @@ fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
219342
}
220343
}
221344

222-
fn type_parameters_covered_by_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
223-
ty: Ty<'tcx>)
224-
-> HashSet<Ty<'tcx>>
225-
{
226-
if ty_is_local_constructor(tcx, ty) {
227-
type_parameters_reachable_from_ty(ty)
228-
} else {
229-
ty.walk_children().flat_map(|t| type_parameters_covered_by_ty(tcx, t).into_iter()).collect()
230-
}
231-
}
232-
233-
/// All type parameters reachable from `ty`
234-
fn type_parameters_reachable_from_ty<'tcx>(ty: Ty<'tcx>) -> HashSet<Ty<'tcx>> {
235-
ty.walk().filter(|&t| is_type_parameter(t)).collect()
236-
}
237-
238-
fn references_local_or_type_parameter<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
239-
ty.walk().any(|ty| is_type_parameter(ty) || ty_is_local_constructor(tcx, ty))
240-
}
241345

242-
fn is_type_parameter<'tcx>(ty: Ty<'tcx>) -> bool {
243-
match ty.sty {
244-
// FIXME(#20590) straighten story about projection types
245-
ty::ty_projection(..) | ty::ty_param(..) => true,
246-
_ => false,
247-
}
248-
}

0 commit comments

Comments
 (0)