diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index dfb9824094346..ab6494e885428 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -186,7 +186,13 @@ impl<'tcx> InherentCollect<'tcx> { return; }; - let self_ty = self.tcx.type_of(item.owner_id); + let mut self_ty = self.tcx.type_of(item.owner_id); + if matches!(self_ty.kind(), ty::Alias(ty::AliasKind::Projection, _)) { + let param_env = self.tcx.param_env(item.owner_id); + if let Ok(new_ty) = self.tcx.try_normalize_erasing_regions(param_env, self_ty) { + self_ty = new_ty; + } + } match *self_ty.kind() { ty::Adt(def, _) => { self.check_def_id(item, self_ty, def.did()); diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 9a5d3cceb914e..fc7e3618e33ce 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -339,7 +339,15 @@ trait VisibilityLike: Sized { effective_visibilities: &EffectiveVisibilities, ) -> Self { let mut find = FindMin { tcx, effective_visibilities, min: Self::MAX }; - find.visit(tcx.type_of(def_id)); + let mut ty = tcx.type_of(def_id); + let param_env = tcx.param_env(def_id); + // We need this normalization when we check the visibility of a projection so it is applied + // to the item behind the projection and not to the projection itself. + ty = match tcx.try_normalize_erasing_regions(param_env, ty) { + Ok(new_ty) => new_ty, + Err(_) => ty, + }; + find.visit(ty); if let Some(trait_ref) = tcx.impl_trait_ref(def_id) { find.visit_trait(trait_ref.subst_identity()); } diff --git a/tests/ui/privacy/private-in-public-ill-formed.rs b/tests/ui/privacy/private-in-public-ill-formed.rs index 031e2874a2ba8..c2b0e5750de31 100644 --- a/tests/ui/privacy/private-in-public-ill-formed.rs +++ b/tests/ui/privacy/private-in-public-ill-formed.rs @@ -12,8 +12,10 @@ mod aliases_pub { } impl ::AssocAlias { - //~^ ERROR no nominal type found for inherent implementation - pub fn f(arg: Priv) {} // private type `aliases_pub::Priv` in public interface + pub fn f(arg: Priv) {} + //~^ ERROR private type `aliases_pub::Priv` in public interface + //~| ERROR private type `aliases_pub::Priv` in public interface + //~| ERROR private trait `aliases_pub::PrivTr` in public interface } } @@ -29,7 +31,6 @@ mod aliases_priv { } impl ::AssocAlias { - //~^ ERROR no nominal type found for inherent implementation pub fn f(arg: Priv) {} // OK } } diff --git a/tests/ui/privacy/private-in-public-ill-formed.stderr b/tests/ui/privacy/private-in-public-ill-formed.stderr index e7c94bc301bdf..10c6e51d2d498 100644 --- a/tests/ui/privacy/private-in-public-ill-formed.stderr +++ b/tests/ui/privacy/private-in-public-ill-formed.stderr @@ -1,19 +1,31 @@ -error[E0118]: no nominal type found for inherent implementation - --> $DIR/private-in-public-ill-formed.rs:14:10 +error[E0446]: private type `aliases_pub::Priv` in public interface + --> $DIR/private-in-public-ill-formed.rs:15:9 | -LL | impl ::AssocAlias { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl requires a nominal type - | - = note: either implement a trait on it or create a newtype to wrap it instead +LL | struct Priv; + | ----------- `aliases_pub::Priv` declared as private +... +LL | pub fn f(arg: Priv) {} + | ^^^^^^^^^^^^^^^^^^^ can't leak private type -error[E0118]: no nominal type found for inherent implementation - --> $DIR/private-in-public-ill-formed.rs:31:10 +error[E0445]: private trait `aliases_pub::PrivTr` in public interface + --> $DIR/private-in-public-ill-formed.rs:15:9 | -LL | impl ::AssocAlias { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl requires a nominal type +LL | trait PrivTr { + | ------------ `aliases_pub::PrivTr` declared as private +... +LL | pub fn f(arg: Priv) {} + | ^^^^^^^^^^^^^^^^^^^ can't leak private trait + +error[E0446]: private type `aliases_pub::Priv` in public interface + --> $DIR/private-in-public-ill-formed.rs:15:9 | - = note: either implement a trait on it or create a newtype to wrap it instead +LL | struct Priv; + | ----------- `aliases_pub::Priv` declared as private +... +LL | pub fn f(arg: Priv) {} + | ^^^^^^^^^^^^^^^^^^^ can't leak private type -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0118`. +Some errors have detailed explanations: E0445, E0446. +For more information about an error, try `rustc --explain E0445`. diff --git a/tests/ui/projection/impl-foreign.rs b/tests/ui/projection/impl-foreign.rs new file mode 100644 index 0000000000000..73761a7f9045e --- /dev/null +++ b/tests/ui/projection/impl-foreign.rs @@ -0,0 +1,13 @@ +#![crate_type = "lib"] + +pub trait Identity { + type Identity: ?Sized; +} + +impl Identity for T { + type Identity = Self; +} + +impl ::Identity { //~ ERROR + pub fn foo(&self) {} +} diff --git a/tests/ui/projection/impl-foreign.stderr b/tests/ui/projection/impl-foreign.stderr new file mode 100644 index 0000000000000..04e626c4a4d32 --- /dev/null +++ b/tests/ui/projection/impl-foreign.stderr @@ -0,0 +1,13 @@ +error[E0116]: cannot define inherent `impl` for a type outside of the crate where the type is defined + --> $DIR/impl-foreign.rs:11:1 + | +LL | / impl ::Identity { +LL | | pub fn foo(&self) {} +LL | | } + | |_^ impl for type defined outside of crate. + | + = note: define and implement a trait or new type instead + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0116`. diff --git a/tests/ui/projection/impl-on-assoc-const.rs b/tests/ui/projection/impl-on-assoc-const.rs new file mode 100644 index 0000000000000..4149ed71b75be --- /dev/null +++ b/tests/ui/projection/impl-on-assoc-const.rs @@ -0,0 +1,15 @@ +#![crate_type = "lib"] + +pub trait Identity { + const Identity: u32; +} + +impl Identity for T { + const Identity: u32 = 0; +} + +pub struct S; + +impl ::Identity { //~ ERROR + pub fn foo(&self) {} +} diff --git a/tests/ui/projection/impl-on-assoc-const.stderr b/tests/ui/projection/impl-on-assoc-const.stderr new file mode 100644 index 0000000000000..d99b0731bc487 --- /dev/null +++ b/tests/ui/projection/impl-on-assoc-const.stderr @@ -0,0 +1,9 @@ +error[E0575]: expected associated type, found associated constant `Identity::Identity` + --> $DIR/impl-on-assoc-const.rs:13:6 + | +LL | impl ::Identity { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ not a associated type + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0575`. diff --git a/tests/ui/projection/impl-on-weird-projection.rs b/tests/ui/projection/impl-on-weird-projection.rs new file mode 100644 index 0000000000000..bb9332652ed8f --- /dev/null +++ b/tests/ui/projection/impl-on-weird-projection.rs @@ -0,0 +1,16 @@ +//~ ERROR +#![crate_type = "lib"] + +pub trait Identity { + type Identity: ?Sized; +} + +impl Identity for T { + type Identity = Self; +} + +pub struct I8; + +impl as Identity>::Identity { + pub fn foo(&self) {} +} diff --git a/tests/ui/projection/impl-on-weird-projection.stderr b/tests/ui/projection/impl-on-weird-projection.stderr new file mode 100644 index 0000000000000..11b8b09cfc422 --- /dev/null +++ b/tests/ui/projection/impl-on-weird-projection.stderr @@ -0,0 +1,76 @@ +error[E0391]: cycle detected when finding all inherent impls defined in crate + | + = note: ...which requires normalizing ` as Identity>::Identity`... +note: ...which requires evaluating type-level constant... + --> $DIR/impl-on-weird-projection.rs:14:10 + | +LL | impl as Identity>::Identity { + | ^^^^^^^^^ +note: ...which requires const-evaluating + checking `::{constant#0}`... + --> $DIR/impl-on-weird-projection.rs:14:10 + | +LL | impl as Identity>::Identity { + | ^^^^^^^^^ +note: ...which requires const-evaluating + checking `::{constant#0}`... + --> $DIR/impl-on-weird-projection.rs:14:10 + | +LL | impl as Identity>::Identity { + | ^^^^^^^^^ +note: ...which requires caching MIR for CTFE of the const argument `::{constant#0}`... + --> $DIR/impl-on-weird-projection.rs:14:10 + | +LL | impl as Identity>::Identity { + | ^^^^^^^^^ +note: ...which requires elaborating drops for `::{constant#0}`... + --> $DIR/impl-on-weird-projection.rs:14:10 + | +LL | impl as Identity>::Identity { + | ^^^^^^^^^ +note: ...which requires borrow-checking the const argument`::{constant#0}`... + --> $DIR/impl-on-weird-projection.rs:14:10 + | +LL | impl as Identity>::Identity { + | ^^^^^^^^^ +note: ...which requires processing MIR for the const argument `::{constant#0}`... + --> $DIR/impl-on-weird-projection.rs:14:10 + | +LL | impl as Identity>::Identity { + | ^^^^^^^^^ +note: ...which requires const checking the const argument `::{constant#0}`... + --> $DIR/impl-on-weird-projection.rs:14:10 + | +LL | impl as Identity>::Identity { + | ^^^^^^^^^ +note: ...which requires preparing the const argument `::{constant#0}` for borrow checking... + --> $DIR/impl-on-weird-projection.rs:14:10 + | +LL | impl as Identity>::Identity { + | ^^^^^^^^^ +note: ...which requires unsafety-checking the const argument `::{constant#0}`... + --> $DIR/impl-on-weird-projection.rs:14:10 + | +LL | impl as Identity>::Identity { + | ^^^^^^^^^ +note: ...which requires building MIR for `::{constant#0}`... + --> $DIR/impl-on-weird-projection.rs:14:10 + | +LL | impl as Identity>::Identity { + | ^^^^^^^^^ +note: ...which requires building THIR for `::{constant#0}`... + --> $DIR/impl-on-weird-projection.rs:14:10 + | +LL | impl as Identity>::Identity { + | ^^^^^^^^^ +note: ...which requires type-checking the const argument `::{constant#0}`... + --> $DIR/impl-on-weird-projection.rs:14:10 + | +LL | impl as Identity>::Identity { + | ^^^^^^^^^ + = note: ...which requires collecting all inherent impls for `IntSimplifiedType(I8)`... + = note: ...which requires collecting all impls for a type in a crate... + = note: ...which again requires finding all inherent impls defined in crate, completing the cycle + = note: cycle used when running analysis passes on this crate + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/projection/impl-projection-on-primitive.rs b/tests/ui/projection/impl-projection-on-primitive.rs new file mode 100644 index 0000000000000..b14740d35ea92 --- /dev/null +++ b/tests/ui/projection/impl-projection-on-primitive.rs @@ -0,0 +1,15 @@ +#![crate_type = "lib"] + +pub trait Identity { + type Identity: ?Sized; +} + +impl Identity for T { + type Identity = (); +} + +pub struct S; + +impl ::Identity { //~ ERROR + pub fn foo(&self) {} +} diff --git a/tests/ui/projection/impl-projection-on-primitive.stderr b/tests/ui/projection/impl-projection-on-primitive.stderr new file mode 100644 index 0000000000000..c944b368105fd --- /dev/null +++ b/tests/ui/projection/impl-projection-on-primitive.stderr @@ -0,0 +1,11 @@ +error[E0390]: cannot define inherent `impl` for primitive types + --> $DIR/impl-projection-on-primitive.rs:13:6 + | +LL | impl ::Identity { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an extension trait instead + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0390`. diff --git a/tests/ui/projection/impl-projection.rs b/tests/ui/projection/impl-projection.rs new file mode 100644 index 0000000000000..a63a760dacdfd --- /dev/null +++ b/tests/ui/projection/impl-projection.rs @@ -0,0 +1,23 @@ +// check-pass + +#![crate_type = "lib"] + +pub trait Identity { + type Identity: ?Sized; +} + +impl Identity for T { + type Identity = Self; +} + +pub struct S; + +impl ::Identity { + pub fn foo(&self) {} +} + +impl S { + pub fn bar(&self) { + self.foo(); + } +} diff --git a/tests/ui/projection/impl-projection2.rs b/tests/ui/projection/impl-projection2.rs new file mode 100644 index 0000000000000..2f173455eae90 --- /dev/null +++ b/tests/ui/projection/impl-projection2.rs @@ -0,0 +1,24 @@ +// check-pass + +#![crate_type = "lib"] + +pub trait Identity { + type Identity: ?Sized; +} + +impl Identity for T { + type Identity = S; +} + +pub struct S; +pub struct Bar; + +impl ::Identity { + pub fn foo(&self) {} +} + +impl S { + pub fn bar(&self) { + self.foo(); + } +}