Skip to content

Commit 3512a72

Browse files
committed
Implement the re-rebalance coherence rfc
1 parent a2b0f24 commit 3512a72

File tree

2 files changed

+98
-30
lines changed

2 files changed

+98
-30
lines changed

src/librustc/traits/coherence.rs

Lines changed: 95 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -344,43 +344,108 @@ fn orphan_check_trait_ref<'tcx>(tcx: TyCtxt<'_, '_, '_>,
344344
trait_ref);
345345
}
346346

347-
// First, create an ordered iterator over all the type parameters to the trait, with the self
348-
// type appearing first.
349-
// Find the first input type that either references a type parameter OR
350-
// some local type.
351-
for input_ty in trait_ref.input_types() {
352-
if ty_is_local(tcx, input_ty, in_crate) {
353-
debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty);
354-
355-
// First local input type. Check that there are no
356-
// uncovered type parameters.
357-
let uncovered_tys = uncovered_tys(tcx, input_ty, in_crate);
358-
for uncovered_ty in uncovered_tys {
359-
if let Some(param) = uncovered_ty.walk()
360-
.find(|t| is_possibly_remote_type(t, in_crate))
361-
{
362-
debug!("orphan_check_trait_ref: uncovered type `{:?}`", param);
363-
return Err(OrphanCheckErr::UncoveredTy(param));
347+
if tcx.features().re_rebalance_coherence {
348+
// Given impl<P1..=Pn> Trait<T1..=Tn> for T0, an impl is valid only
349+
// if at least one of the following is true:
350+
//
351+
// - Trait is a local trait
352+
// (already checked in orphan_check prior to calling this function)
353+
// - All of
354+
// - At least one of the types T0..=Tn must be a local type.
355+
// Let Ti be the first such type.
356+
// - No uncovered type parameters P1..=Pn may appear in T0..Ti (excluding Ti)
357+
//
358+
for input_ty in trait_ref.input_types() {
359+
debug!("orphan_check_trait_ref: check ty `{:?}`", input_ty);
360+
if ty_is_local(tcx, input_ty, in_crate) {
361+
debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty);
362+
return Ok(());
363+
} else if is_uncovered_ty(input_ty) {
364+
debug!("orphan_check_trait_ref: uncovered ty: `{:?}`", input_ty);
365+
return Err(OrphanCheckErr::UncoveredTy(input_ty))
366+
}
367+
}
368+
// If we exit above loop, never found a local type.
369+
debug!("orphan_check_trait_ref: no local type");
370+
Err(OrphanCheckErr::NoLocalInputType)
371+
} else {
372+
// First, create an ordered iterator over all the type parameters to the trait, with the self
373+
// type appearing first.
374+
// Find the first input type that either references a type parameter OR
375+
// some local type.
376+
for input_ty in trait_ref.input_types() {
377+
if ty_is_local(tcx, input_ty, in_crate) {
378+
debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty);
379+
380+
// First local input type. Check that there are no
381+
// uncovered type parameters.
382+
let uncovered_tys = uncovered_tys(tcx, input_ty, in_crate);
383+
for uncovered_ty in uncovered_tys {
384+
if let Some(param) = uncovered_ty.walk()
385+
.find(|t| is_possibly_remote_type(t, in_crate))
386+
{
387+
debug!("orphan_check_trait_ref: uncovered type `{:?}`", param);
388+
return Err(OrphanCheckErr::UncoveredTy(param));
389+
}
364390
}
391+
392+
// OK, found local type, all prior types upheld invariant.
393+
return Ok(());
365394
}
366395

367-
// OK, found local type, all prior types upheld invariant.
368-
return Ok(());
396+
// Otherwise, enforce invariant that there are no type
397+
// parameters reachable.
398+
if let Some(param) = input_ty.walk()
399+
.find(|t| is_possibly_remote_type(t, in_crate))
400+
{
401+
debug!("orphan_check_trait_ref: uncovered type `{:?}`", param);
402+
return Err(OrphanCheckErr::UncoveredTy(param));
403+
}
404+
}
405+
// If we exit above loop, never found a local type.
406+
debug!("orphan_check_trait_ref: no local type");
407+
Err(OrphanCheckErr::NoLocalInputType)
408+
}
409+
}
410+
411+
fn is_uncovered_ty(ty: Ty<'_>) -> bool {
412+
match ty.sty {
413+
ty::Bool |
414+
ty::Char |
415+
ty::Int(..) |
416+
ty::Uint(..) |
417+
ty::Float(..) |
418+
ty::Str |
419+
ty::FnDef(..) |
420+
ty::FnPtr(_) |
421+
ty::Array(..) |
422+
ty::Slice(..) |
423+
ty::RawPtr(..) |
424+
ty::Ref(..) |
425+
ty::Never |
426+
ty::Tuple(..) |
427+
ty::Bound(..) |
428+
ty::Infer(..) |
429+
ty::Adt(..) |
430+
ty::Foreign(..) |
431+
ty::Dynamic(..) |
432+
ty::Error |
433+
ty::Projection(..) => {
434+
false
435+
}
436+
437+
ty::Param(..) => {
438+
true
369439
}
370440

371-
// Otherwise, enforce invariant that there are no type
372-
// parameters reachable.
373-
if let Some(param) = input_ty.walk()
374-
.find(|t| is_possibly_remote_type(t, in_crate))
375-
{
376-
debug!("orphan_check_trait_ref: uncovered type `{:?}`", param);
377-
return Err(OrphanCheckErr::UncoveredTy(param));
441+
ty::UnnormalizedProjection(..) |
442+
ty::Closure(..) |
443+
ty::Generator(..) |
444+
ty::GeneratorWitness(..) |
445+
ty::Opaque(..) => {
446+
bug!("is_uncovered_ty invoked on unexpected type: {:?}", ty)
378447
}
379448
}
380-
381-
// If we exit above loop, never found a local type.
382-
debug!("orphan_check_trait_ref: no local type");
383-
return Err(OrphanCheckErr::NoLocalInputType);
384449
}
385450

386451
fn uncovered_tys<'tcx>(tcx: TyCtxt<'_, '_, '_>, ty: Ty<'tcx>, in_crate: InCrate)

src/libsyntax/feature_gate.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,9 @@ declare_features! (
479479

480480
// Allows paths to enum variants on type aliases.
481481
(active, type_alias_enum_variants, "1.31.0", Some(49683), None),
482+
483+
// Re-Rebalance coherence
484+
(active, re_rebalance_coherence, "1.32.0", Some(55437), None),
482485
);
483486

484487
declare_features! (

0 commit comments

Comments
 (0)