Skip to content

Commit 757d7ba

Browse files
committed
Implement the re-rebalance coherence rfc
1 parent c0bbc39 commit 757d7ba

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
@@ -371,43 +371,108 @@ fn orphan_check_trait_ref<'tcx>(tcx: TyCtxt<'_, '_, '_>,
371371
trait_ref);
372372
}
373373

374-
// First, create an ordered iterator over all the type parameters to the trait, with the self
375-
// type appearing first.
376-
// Find the first input type that either references a type parameter OR
377-
// some local type.
378-
for input_ty in trait_ref.input_types() {
379-
if ty_is_local(tcx, input_ty, in_crate) {
380-
debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty);
381-
382-
// First local input type. Check that there are no
383-
// uncovered type parameters.
384-
let uncovered_tys = uncovered_tys(tcx, input_ty, in_crate);
385-
for uncovered_ty in uncovered_tys {
386-
if let Some(param) = uncovered_ty.walk()
387-
.find(|t| is_possibly_remote_type(t, in_crate))
388-
{
389-
debug!("orphan_check_trait_ref: uncovered type `{:?}`", param);
390-
return Err(OrphanCheckErr::UncoveredTy(param));
374+
if tcx.features().re_rebalance_coherence {
375+
// Given impl<P1..=Pn> Trait<T1..=Tn> for T0, an impl is valid only
376+
// if at least one of the following is true:
377+
//
378+
// - Trait is a local trait
379+
// (already checked in orphan_check prior to calling this function)
380+
// - All of
381+
// - At least one of the types T0..=Tn must be a local type.
382+
// Let Ti be the first such type.
383+
// - No uncovered type parameters P1..=Pn may appear in T0..Ti (excluding Ti)
384+
//
385+
for input_ty in trait_ref.input_types() {
386+
debug!("orphan_check_trait_ref: check ty `{:?}`", input_ty);
387+
if ty_is_local(tcx, input_ty, in_crate) {
388+
debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty);
389+
return Ok(());
390+
} else if is_uncovered_ty(input_ty) {
391+
debug!("orphan_check_trait_ref: uncovered ty: `{:?}`", input_ty);
392+
return Err(OrphanCheckErr::UncoveredTy(input_ty))
393+
}
394+
}
395+
// If we exit above loop, never found a local type.
396+
debug!("orphan_check_trait_ref: no local type");
397+
Err(OrphanCheckErr::NoLocalInputType)
398+
} else {
399+
// First, create an ordered iterator over all the type parameters to the trait, with the self
400+
// type appearing first.
401+
// Find the first input type that either references a type parameter OR
402+
// some local type.
403+
for input_ty in trait_ref.input_types() {
404+
if ty_is_local(tcx, input_ty, in_crate) {
405+
debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty);
406+
407+
// First local input type. Check that there are no
408+
// uncovered type parameters.
409+
let uncovered_tys = uncovered_tys(tcx, input_ty, in_crate);
410+
for uncovered_ty in uncovered_tys {
411+
if let Some(param) = uncovered_ty.walk()
412+
.find(|t| is_possibly_remote_type(t, in_crate))
413+
{
414+
debug!("orphan_check_trait_ref: uncovered type `{:?}`", param);
415+
return Err(OrphanCheckErr::UncoveredTy(param));
416+
}
391417
}
418+
419+
// OK, found local type, all prior types upheld invariant.
420+
return Ok(());
392421
}
393422

394-
// OK, found local type, all prior types upheld invariant.
395-
return Ok(());
423+
// Otherwise, enforce invariant that there are no type
424+
// parameters reachable.
425+
if let Some(param) = input_ty.walk()
426+
.find(|t| is_possibly_remote_type(t, in_crate))
427+
{
428+
debug!("orphan_check_trait_ref: uncovered type `{:?}`", param);
429+
return Err(OrphanCheckErr::UncoveredTy(param));
430+
}
431+
}
432+
// If we exit above loop, never found a local type.
433+
debug!("orphan_check_trait_ref: no local type");
434+
Err(OrphanCheckErr::NoLocalInputType)
435+
}
436+
}
437+
438+
fn is_uncovered_ty(ty: Ty<'_>) -> bool {
439+
match ty.sty {
440+
ty::Bool |
441+
ty::Char |
442+
ty::Int(..) |
443+
ty::Uint(..) |
444+
ty::Float(..) |
445+
ty::Str |
446+
ty::FnDef(..) |
447+
ty::FnPtr(_) |
448+
ty::Array(..) |
449+
ty::Slice(..) |
450+
ty::RawPtr(..) |
451+
ty::Ref(..) |
452+
ty::Never |
453+
ty::Tuple(..) |
454+
ty::Bound(..) |
455+
ty::Infer(..) |
456+
ty::Adt(..) |
457+
ty::Foreign(..) |
458+
ty::Dynamic(..) |
459+
ty::Error |
460+
ty::Projection(..) => {
461+
false
462+
}
463+
464+
ty::Param(..) => {
465+
true
396466
}
397467

398-
// Otherwise, enforce invariant that there are no type
399-
// parameters reachable.
400-
if let Some(param) = input_ty.walk()
401-
.find(|t| is_possibly_remote_type(t, in_crate))
402-
{
403-
debug!("orphan_check_trait_ref: uncovered type `{:?}`", param);
404-
return Err(OrphanCheckErr::UncoveredTy(param));
468+
ty::UnnormalizedProjection(..) |
469+
ty::Closure(..) |
470+
ty::Generator(..) |
471+
ty::GeneratorWitness(..) |
472+
ty::Opaque(..) => {
473+
bug!("is_uncovered_ty invoked on unexpected type: {:?}", ty)
405474
}
406475
}
407-
408-
// If we exit above loop, never found a local type.
409-
debug!("orphan_check_trait_ref: no local type");
410-
return Err(OrphanCheckErr::NoLocalInputType);
411476
}
412477

413478
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)