Skip to content

Commit 515dce5

Browse files
authored
Rollup merge of rust-lang#65318 - estebank:coherence, r=varkor
Call out the types that are non local on E0117 CC rust-lang#24745.
2 parents a3fa189 + 627691f commit 515dce5

File tree

69 files changed

+467
-250
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+467
-250
lines changed

src/librustc/traits/coherence.rs

+77-30
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ pub fn trait_ref_is_local_or_fundamental<'tcx>(
237237
}
238238

239239
pub enum OrphanCheckErr<'tcx> {
240-
NoLocalInputType,
240+
NonLocalInputType(Vec<(Ty<'tcx>, bool /* Is this the first input type? */)>),
241241
UncoveredTy(Ty<'tcx>),
242242
}
243243

@@ -355,7 +355,7 @@ pub fn orphan_check(
355355
/// Note that this function is never called for types that have both type
356356
/// parameters and inference variables.
357357
fn orphan_check_trait_ref<'tcx>(
358-
tcx: TyCtxt<'_>,
358+
tcx: TyCtxt<'tcx>,
359359
trait_ref: ty::TraitRef<'tcx>,
360360
in_crate: InCrate,
361361
) -> Result<(), OrphanCheckErr<'tcx>> {
@@ -378,40 +378,51 @@ fn orphan_check_trait_ref<'tcx>(
378378
// Let Ti be the first such type.
379379
// - No uncovered type parameters P1..=Pn may appear in T0..Ti (excluding Ti)
380380
//
381-
fn uncover_fundamental_ty<'a>(
382-
tcx: TyCtxt<'_>,
383-
ty: Ty<'a>,
381+
fn uncover_fundamental_ty<'tcx>(
382+
tcx: TyCtxt<'tcx>,
383+
ty: Ty<'tcx>,
384384
in_crate: InCrate,
385-
) -> Vec<Ty<'a>> {
386-
if fundamental_ty(ty) && !ty_is_local(tcx, ty, in_crate) {
385+
) -> Vec<Ty<'tcx>> {
386+
if fundamental_ty(ty) && ty_is_non_local(tcx, ty, in_crate).is_some() {
387387
ty.walk_shallow().flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)).collect()
388388
} else {
389389
vec![ty]
390390
}
391391
}
392392

393-
for input_ty in
394-
trait_ref.input_types().flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
393+
let mut non_local_spans = vec![];
394+
for (i, input_ty) in trait_ref
395+
.input_types()
396+
.flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
397+
.enumerate()
395398
{
396399
debug!("orphan_check_trait_ref: check ty `{:?}`", input_ty);
397-
if ty_is_local(tcx, input_ty, in_crate) {
400+
let non_local_tys = ty_is_non_local(tcx, input_ty, in_crate);
401+
if non_local_tys.is_none() {
398402
debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty);
399403
return Ok(());
400404
} else if let ty::Param(_) = input_ty.kind {
401405
debug!("orphan_check_trait_ref: uncovered ty: `{:?}`", input_ty);
402406
return Err(OrphanCheckErr::UncoveredTy(input_ty))
403407
}
408+
if let Some(non_local_tys) = non_local_tys {
409+
for input_ty in non_local_tys {
410+
non_local_spans.push((input_ty, i == 0));
411+
}
412+
}
404413
}
405414
// If we exit above loop, never found a local type.
406415
debug!("orphan_check_trait_ref: no local type");
407-
Err(OrphanCheckErr::NoLocalInputType)
416+
Err(OrphanCheckErr::NonLocalInputType(non_local_spans))
408417
} else {
418+
let mut non_local_spans = vec![];
409419
// First, create an ordered iterator over all the type
410420
// parameters to the trait, with the self type appearing
411421
// first. Find the first input type that either references a
412422
// type parameter OR some local type.
413-
for input_ty in trait_ref.input_types() {
414-
if ty_is_local(tcx, input_ty, in_crate) {
423+
for (i, input_ty) in trait_ref.input_types().enumerate() {
424+
let non_local_tys = ty_is_non_local(tcx, input_ty, in_crate);
425+
if non_local_tys.is_none() {
415426
debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty);
416427

417428
// First local input type. Check that there are no
@@ -438,15 +449,21 @@ fn orphan_check_trait_ref<'tcx>(
438449
debug!("orphan_check_trait_ref: uncovered type `{:?}`", param);
439450
return Err(OrphanCheckErr::UncoveredTy(param));
440451
}
452+
453+
if let Some(non_local_tys) = non_local_tys {
454+
for input_ty in non_local_tys {
455+
non_local_spans.push((input_ty, i == 0));
456+
}
457+
}
441458
}
442459
// If we exit above loop, never found a local type.
443460
debug!("orphan_check_trait_ref: no local type");
444-
Err(OrphanCheckErr::NoLocalInputType)
461+
Err(OrphanCheckErr::NonLocalInputType(non_local_spans))
445462
}
446463
}
447464

448-
fn uncovered_tys<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, in_crate: InCrate) -> Vec<Ty<'tcx>> {
449-
if ty_is_local_constructor(tcx, ty, in_crate) {
465+
fn uncovered_tys<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, in_crate: InCrate) -> Vec<Ty<'tcx>> {
466+
if ty_is_non_local_constructor(tcx, ty, in_crate).is_none() {
450467
vec![]
451468
} else if fundamental_ty(ty) {
452469
ty.walk_shallow()
@@ -464,9 +481,23 @@ fn is_possibly_remote_type(ty: Ty<'_>, _in_crate: InCrate) -> bool {
464481
}
465482
}
466483

467-
fn ty_is_local(tcx: TyCtxt<'_>, ty: Ty<'_>, in_crate: InCrate) -> bool {
468-
ty_is_local_constructor(tcx, ty, in_crate) ||
469-
fundamental_ty(ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, in_crate))
484+
fn ty_is_non_local<'t>(tcx: TyCtxt<'t>, ty: Ty<'t>, in_crate: InCrate) -> Option<Vec<Ty<'t>>> {
485+
match ty_is_non_local_constructor(tcx, ty, in_crate) {
486+
Some(ty) => if !fundamental_ty(ty) {
487+
Some(vec![ty])
488+
} else {
489+
let tys: Vec<_> = ty.walk_shallow()
490+
.filter_map(|t| ty_is_non_local(tcx, t, in_crate))
491+
.flat_map(|i| i)
492+
.collect();
493+
if tys.is_empty() {
494+
None
495+
} else {
496+
Some(tys)
497+
}
498+
},
499+
None => None,
500+
}
470501
}
471502

472503
fn fundamental_ty(ty: Ty<'_>) -> bool {
@@ -486,8 +517,12 @@ fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool {
486517
}
487518
}
488519

489-
fn ty_is_local_constructor(tcx: TyCtxt<'_>, ty: Ty<'_>, in_crate: InCrate) -> bool {
490-
debug!("ty_is_local_constructor({:?})", ty);
520+
fn ty_is_non_local_constructor<'tcx>(
521+
tcx: TyCtxt<'tcx>,
522+
ty: Ty<'tcx>,
523+
in_crate: InCrate,
524+
) -> Option<Ty<'tcx>> {
525+
debug!("ty_is_non_local_constructor({:?})", ty);
491526

492527
match ty.kind {
493528
ty::Bool |
@@ -506,37 +541,49 @@ fn ty_is_local_constructor(tcx: TyCtxt<'_>, ty: Ty<'_>, in_crate: InCrate) -> bo
506541
ty::Tuple(..) |
507542
ty::Param(..) |
508543
ty::Projection(..) => {
509-
false
544+
Some(ty)
510545
}
511546

512547
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => match in_crate {
513-
InCrate::Local => false,
548+
InCrate::Local => Some(ty),
514549
// The inference variable might be unified with a local
515550
// type in that remote crate.
516-
InCrate::Remote => true,
551+
InCrate::Remote => None,
517552
},
518553

519-
ty::Adt(def, _) => def_id_is_local(def.did, in_crate),
520-
ty::Foreign(did) => def_id_is_local(did, in_crate),
554+
ty::Adt(def, _) => if def_id_is_local(def.did, in_crate) {
555+
None
556+
} else {
557+
Some(ty)
558+
},
559+
ty::Foreign(did) => if def_id_is_local(did, in_crate) {
560+
None
561+
} else {
562+
Some(ty)
563+
},
521564
ty::Opaque(did, _) => {
522565
// Check the underlying type that this opaque
523566
// type resolves to.
524567
// This recursion will eventually terminate,
525568
// since we've already managed to successfully
526569
// resolve all opaque types by this point
527570
let real_ty = tcx.type_of(did);
528-
ty_is_local_constructor(tcx, real_ty, in_crate)
571+
ty_is_non_local_constructor(tcx, real_ty, in_crate)
529572
}
530573

531574
ty::Dynamic(ref tt, ..) => {
532575
if let Some(principal) = tt.principal() {
533-
def_id_is_local(principal.def_id(), in_crate)
576+
if def_id_is_local(principal.def_id(), in_crate) {
577+
None
578+
} else {
579+
Some(ty)
580+
}
534581
} else {
535-
false
582+
Some(ty)
536583
}
537584
}
538585

539-
ty::Error => true,
586+
ty::Error => None,
540587

541588
ty::UnnormalizedProjection(..) |
542589
ty::Closure(..) |

src/librustc_typeck/coherence/orphan.rs

+66-24
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> {
2424
fn visit_item(&mut self, item: &hir::Item) {
2525
let def_id = self.tcx.hir().local_def_id(item.hir_id);
2626
// "Trait" impl
27-
if let hir::ItemKind::Impl(.., Some(_), _, _) = item.kind {
27+
if let hir::ItemKind::Impl(.., generics, Some(tr), impl_ty, _) = &item.kind {
2828
debug!("coherence2::orphan check: trait impl {}",
2929
self.tcx.hir().node_to_string(item.hir_id));
3030
let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
@@ -33,32 +33,74 @@ impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> {
3333
let sp = cm.def_span(item.span);
3434
match traits::orphan_check(self.tcx, def_id) {
3535
Ok(()) => {}
36-
Err(traits::OrphanCheckErr::NoLocalInputType) => {
37-
struct_span_err!(self.tcx.sess,
38-
sp,
39-
E0117,
40-
"only traits defined in the current crate can be \
41-
implemented for arbitrary types")
42-
.span_label(sp, "impl doesn't use types inside crate")
43-
.note("the impl does not reference only types defined in this crate")
44-
.note("define and implement a trait or new type instead")
45-
.emit();
36+
Err(traits::OrphanCheckErr::NonLocalInputType(tys)) => {
37+
let mut err = struct_span_err!(
38+
self.tcx.sess,
39+
sp,
40+
E0117,
41+
"only traits defined in the current crate can be implemented for \
42+
arbitrary types"
43+
);
44+
err.span_label(sp, "impl doesn't use only types from inside the current crate");
45+
for (ty, is_target_ty) in &tys {
46+
let mut ty = *ty;
47+
self.tcx.infer_ctxt().enter(|infcx| {
48+
// Remove the lifetimes unnecessary for this error.
49+
ty = infcx.freshen(ty);
50+
});
51+
ty = match ty.kind {
52+
// Remove the type arguments from the output, as they are not relevant.
53+
// You can think of this as the reverse of `resolve_vars_if_possible`.
54+
// That way if we had `Vec<MyType>`, we will properly attribute the
55+
// problem to `Vec<T>` and avoid confusing the user if they were to see
56+
// `MyType` in the error.
57+
ty::Adt(def, _) => self.tcx.mk_adt(def, ty::List::empty()),
58+
_ => ty,
59+
};
60+
let this = "this".to_string();
61+
let (ty, postfix) = match &ty.kind {
62+
ty::Slice(_) => (this, " because slices are always foreign"),
63+
ty::Array(..) => (this, " because arrays are always foreign"),
64+
ty::Tuple(..) => (this, " because tuples are always foreign"),
65+
_ => (format!("`{}`", ty), ""),
66+
};
67+
let msg = format!("{} is not defined in the current crate{}", ty, postfix);
68+
if *is_target_ty {
69+
// Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
70+
err.span_label(impl_ty.span, &msg);
71+
} else {
72+
// Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
73+
err.span_label(tr.path.span, &msg);
74+
}
75+
}
76+
err.note("define and implement a trait or new type instead");
77+
err.emit();
4678
return;
4779
}
4880
Err(traits::OrphanCheckErr::UncoveredTy(param_ty)) => {
49-
struct_span_err!(self.tcx.sess,
50-
sp,
51-
E0210,
52-
"type parameter `{}` must be used as the type parameter \
53-
for some local type (e.g., `MyStruct<{}>`)",
54-
param_ty,
55-
param_ty)
56-
.span_label(sp,
57-
format!("type parameter `{}` must be used as the type \
58-
parameter for some local type", param_ty))
59-
.note("only traits defined in the current crate can be implemented \
60-
for a type parameter")
61-
.emit();
81+
let mut sp = sp;
82+
for param in &generics.params {
83+
if param.name.ident().to_string() == param_ty.to_string() {
84+
sp = param.span;
85+
}
86+
}
87+
let mut err = struct_span_err!(
88+
self.tcx.sess,
89+
sp,
90+
E0210,
91+
"type parameter `{}` must be used as the type parameter for some local \
92+
type (e.g., `MyStruct<{}>`)",
93+
param_ty,
94+
param_ty
95+
);
96+
err.span_label(sp, format!(
97+
"type parameter `{}` must be used as the type parameter for some local \
98+
type",
99+
param_ty,
100+
));
101+
err.note("only traits defined in the current crate can be implemented for a \
102+
type parameter");
103+
err.emit();
62104
return;
63105
}
64106
}

src/test/ui/coherence/coherence-all-remote.old.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
2-
--> $DIR/coherence-all-remote.rs:9:1
2+
--> $DIR/coherence-all-remote.rs:9:6
33
|
44
LL | impl<T> Remote1<T> for isize { }
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type
5+
| ^ type parameter `T` must be used as the type parameter for some local type
66
|
77
= note: only traits defined in the current crate can be implemented for a type parameter
88

src/test/ui/coherence/coherence-all-remote.re.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
2-
--> $DIR/coherence-all-remote.rs:9:1
2+
--> $DIR/coherence-all-remote.rs:9:6
33
|
44
LL | impl<T> Remote1<T> for isize { }
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type
5+
| ^ type parameter `T` must be used as the type parameter for some local type
66
|
77
= note: only traits defined in the current crate can be implemented for a type parameter
88

src/test/ui/coherence/coherence-bigint-param.old.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
2-
--> $DIR/coherence-bigint-param.rs:11:1
2+
--> $DIR/coherence-bigint-param.rs:11:6
33
|
44
LL | impl<T> Remote1<BigInt> for T { }
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type
5+
| ^ type parameter `T` must be used as the type parameter for some local type
66
|
77
= note: only traits defined in the current crate can be implemented for a type parameter
88

src/test/ui/coherence/coherence-bigint-param.re.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
2-
--> $DIR/coherence-bigint-param.rs:11:1
2+
--> $DIR/coherence-bigint-param.rs:11:6
33
|
44
LL | impl<T> Remote1<BigInt> for T { }
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type
5+
| ^ type parameter `T` must be used as the type parameter for some local type
66
|
77
= note: only traits defined in the current crate can be implemented for a type parameter
88

src/test/ui/coherence/coherence-cow.a.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
2-
--> $DIR/coherence-cow.rs:18:1
2+
--> $DIR/coherence-cow.rs:18:6
33
|
44
LL | impl<T> Remote for Pair<T,Cover<T>> { }
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type
5+
| ^ type parameter `T` must be used as the type parameter for some local type
66
|
77
= note: only traits defined in the current crate can be implemented for a type parameter
88

src/test/ui/coherence/coherence-cow.b.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
2-
--> $DIR/coherence-cow.rs:23:1
2+
--> $DIR/coherence-cow.rs:23:6
33
|
44
LL | impl<T> Remote for Pair<Cover<T>,T> { }
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type
5+
| ^ type parameter `T` must be used as the type parameter for some local type
66
|
77
= note: only traits defined in the current crate can be implemented for a type parameter
88

src/test/ui/coherence/coherence-cow.c.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
2-
--> $DIR/coherence-cow.rs:28:1
2+
--> $DIR/coherence-cow.rs:28:6
33
|
44
LL | impl<T,U> Remote for Pair<Cover<T>,U> { }
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type
5+
| ^ type parameter `T` must be used as the type parameter for some local type
66
|
77
= note: only traits defined in the current crate can be implemented for a type parameter
88

0 commit comments

Comments
 (0)