Skip to content

Commit 0d4705b

Browse files
committed
traits/coherence: stop using Ty::walk_shallow.
1 parent e53c42c commit 0d4705b

File tree

2 files changed

+52
-21
lines changed

2 files changed

+52
-21
lines changed

src/librustc_trait_selection/traits/coherence.rs

+50-19
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use rustc_middle::ty::subst::Subst;
1414
use rustc_middle::ty::{self, Ty, TyCtxt};
1515
use rustc_span::symbol::sym;
1616
use rustc_span::DUMMY_SP;
17+
use std::iter;
1718

1819
/// Whether we do the orphan check relative to this crate or
1920
/// to some remote crate.
@@ -378,19 +379,25 @@ fn orphan_check_trait_ref<'tcx>(
378379
ty: Ty<'tcx>,
379380
in_crate: InCrate,
380381
) -> Vec<Ty<'tcx>> {
381-
if fundamental_ty(ty) && ty_is_non_local(ty, in_crate).is_some() {
382-
ty.walk_shallow().flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)).collect()
383-
} else {
384-
vec![ty]
382+
// FIXME(eddyb) figure out if this is redundant with `ty_is_non_local`,
383+
// or maybe if this should be calling `ty_is_non_local_constructor`.
384+
if ty_is_non_local(tcx, ty, in_crate).is_some() {
385+
if let Some(inner_tys) = fundamental_ty_inner_tys(tcx, ty) {
386+
return inner_tys
387+
.flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
388+
.collect();
389+
}
385390
}
391+
392+
vec![ty]
386393
}
387394

388395
let mut non_local_spans = vec![];
389396
for (i, input_ty) in
390397
trait_ref.input_types().flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)).enumerate()
391398
{
392399
debug!("orphan_check_trait_ref: check ty `{:?}`", input_ty);
393-
let non_local_tys = ty_is_non_local(input_ty, in_crate);
400+
let non_local_tys = ty_is_non_local(tcx, input_ty, in_crate);
394401
if non_local_tys.is_none() {
395402
debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty);
396403
return Ok(());
@@ -416,30 +423,53 @@ fn orphan_check_trait_ref<'tcx>(
416423
Err(OrphanCheckErr::NonLocalInputType(non_local_spans))
417424
}
418425

419-
fn ty_is_non_local<'t>(ty: Ty<'t>, in_crate: InCrate) -> Option<Vec<Ty<'t>>> {
426+
fn ty_is_non_local(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, in_crate: InCrate) -> Option<Vec<Ty<'tcx>>> {
420427
match ty_is_non_local_constructor(ty, in_crate) {
421428
Some(ty) => {
422-
if !fundamental_ty(ty) {
423-
Some(vec![ty])
424-
} else {
425-
let tys: Vec<_> = ty
426-
.walk_shallow()
427-
.filter_map(|t| ty_is_non_local(t, in_crate))
428-
.flat_map(|i| i)
429+
if let Some(inner_tys) = fundamental_ty_inner_tys(tcx, ty) {
430+
let tys: Vec<_> = inner_tys
431+
.filter_map(|ty| ty_is_non_local(tcx, ty, in_crate))
432+
.flatten()
429433
.collect();
430434
if tys.is_empty() { None } else { Some(tys) }
435+
} else {
436+
Some(vec![ty])
431437
}
432438
}
433439
None => None,
434440
}
435441
}
436442

437-
fn fundamental_ty(ty: Ty<'_>) -> bool {
438-
match ty.kind {
439-
ty::Ref(..) => true,
440-
ty::Adt(def, _) => def.is_fundamental(),
441-
_ => false,
442-
}
443+
/// For `#[fundamental]` ADTs and `&T` / `&mut T`, returns `Some` with the
444+
/// type parameters of the ADT, or `T`, respectively. For non-fundamental
445+
/// types, returns `None`.
446+
fn fundamental_ty_inner_tys(
447+
tcx: TyCtxt<'tcx>,
448+
ty: Ty<'tcx>,
449+
) -> Option<impl Iterator<Item = Ty<'tcx>>> {
450+
let (first_ty, rest_tys) = match ty.kind {
451+
ty::Ref(_, ty, _) => (ty, ty::subst::InternalSubsts::empty().types()),
452+
ty::Adt(def, substs) if def.is_fundamental() => {
453+
let mut types = substs.types();
454+
455+
// FIXME(eddyb) actually validate `#[fundamental]` up-front.
456+
match types.next() {
457+
None => {
458+
tcx.sess.span_err(
459+
tcx.def_span(def.did),
460+
"`#[fundamental]` requires at least one type parameter",
461+
);
462+
463+
return None;
464+
}
465+
466+
Some(first_ty) => (first_ty, types),
467+
}
468+
}
469+
_ => return None,
470+
};
471+
472+
Some(iter::once(first_ty).chain(rest_tys))
443473
}
444474

445475
fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool {
@@ -451,6 +481,7 @@ fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool {
451481
}
452482
}
453483

484+
// FIXME(eddyb) this can just return `bool` as it always returns `Some(ty)` or `None`.
454485
fn ty_is_non_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> Option<Ty<'_>> {
455486
debug!("ty_is_non_local_constructor({:?})", ty);
456487

src/test/ui/coherence/impl-foreign-for-locally-defined-fundamental.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ extern crate coherence_lib as lib;
88
use lib::*;
99

1010
#[fundamental]
11-
struct Local;
11+
struct Local<T>(T);
1212

13-
impl Remote for Local {}
13+
impl Remote for Local<()> {}
1414

1515
fn main() {}

0 commit comments

Comments
 (0)