1
Fork 0

For non-defining opaque type usage errors, don't try to also prove all trait bounds

This commit is contained in:
Oli Scherer 2022-05-10 14:32:12 +00:00
parent 253408b409
commit 7a4ac84a90
10 changed files with 108 additions and 290 deletions

View file

@ -1,11 +1,8 @@
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::vec_map::VecMap; use rustc_data_structures::vec_map::VecMap;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::OpaqueTyOrigin; use rustc_hir::OpaqueTyOrigin;
use rustc_infer::infer::InferCtxt; use rustc_infer::infer::InferCtxt;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, TyCtxt, TypeFoldable}; use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, TyCtxt, TypeFoldable};
use rustc_span::Span;
use rustc_trait_selection::opaque_types::InferCtxtExt; use rustc_trait_selection::opaque_types::InferCtxtExt;
use super::RegionInferenceContext; use super::RegionInferenceContext;
@ -107,21 +104,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let opaque_type_key = let opaque_type_key =
OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs }; OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs };
let remapped_type = infcx.infer_opaque_definition_from_instantiation( let ty = infcx.infer_opaque_definition_from_instantiation(
opaque_type_key, opaque_type_key,
universal_concrete_type, universal_concrete_type,
origin, origin,
); );
let ty = if check_opaque_type_parameter_valid(
infcx.tcx,
opaque_type_key,
origin,
concrete_type.span,
) {
remapped_type
} else {
infcx.tcx.ty_error()
};
// Sometimes two opaque types are the same only after we remap the generic parameters // Sometimes two opaque types are the same only after we remap the generic parameters
// back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)` // back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)`
// and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we only know that // and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we only know that
@ -184,95 +171,3 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}) })
} }
} }
fn check_opaque_type_parameter_valid(
tcx: TyCtxt<'_>,
opaque_type_key: OpaqueTypeKey<'_>,
origin: OpaqueTyOrigin,
span: Span,
) -> bool {
match origin {
// No need to check return position impl trait (RPIT)
// because for type and const parameters they are correct
// by construction: we convert
//
// fn foo<P0..Pn>() -> impl Trait
//
// into
//
// type Foo<P0...Pn>
// fn foo<P0..Pn>() -> Foo<P0...Pn>.
//
// For lifetime parameters we convert
//
// fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
//
// into
//
// type foo::<'p0..'pn>::Foo<'q0..'qm>
// fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
//
// which would error here on all of the `'static` args.
OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true,
// Check these
OpaqueTyOrigin::TyAlias => {}
}
let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default();
for (i, arg) in opaque_type_key.substs.iter().enumerate() {
let arg_is_param = match arg.unpack() {
GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
GenericArgKind::Lifetime(lt) if lt.is_static() => {
tcx.sess
.struct_span_err(span, "non-defining opaque type use in defining scope")
.span_label(
tcx.def_span(opaque_generics.param_at(i, tcx).def_id),
"cannot use static lifetime; use a bound lifetime \
instead or remove the lifetime parameter from the \
opaque type",
)
.emit();
return false;
}
GenericArgKind::Lifetime(lt) => {
matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
}
GenericArgKind::Const(ct) => matches!(ct.val(), ty::ConstKind::Param(_)),
};
if arg_is_param {
seen_params.entry(arg).or_default().push(i);
} else {
// Prevent `fn foo() -> Foo<u32>` from being defining.
let opaque_param = opaque_generics.param_at(i, tcx);
tcx.sess
.struct_span_err(span, "non-defining opaque type use in defining scope")
.span_note(
tcx.def_span(opaque_param.def_id),
&format!(
"used non-generic {} `{}` for generic parameter",
opaque_param.kind.descr(),
arg,
),
)
.emit();
return false;
}
}
for (_, indices) in seen_params {
if indices.len() > 1 {
let descr = opaque_generics.param_at(indices[0], tcx).kind.descr();
let spans: Vec<_> = indices
.into_iter()
.map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
.collect();
tcx.sess
.struct_span_err(span, "non-defining opaque type use in defining scope")
.span_note(spans, &format!("{} used multiple times", descr))
.emit();
return false;
}
}
true
}

View file

@ -82,6 +82,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
)); ));
debug!(?definition_ty); debug!(?definition_ty);
if !check_opaque_type_parameter_valid(
self.tcx,
opaque_type_key,
origin,
instantiated_ty.span,
) {
return self.tcx.ty_error();
}
// Only check this for TAIT. RPIT already supports `src/test/ui/impl-trait/nested-return-type2.rs` // Only check this for TAIT. RPIT already supports `src/test/ui/impl-trait/nested-return-type2.rs`
// on stable and we'd break that. // on stable and we'd break that.
if let OpaqueTyOrigin::TyAlias = origin { if let OpaqueTyOrigin::TyAlias = origin {
@ -148,6 +157,98 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
} }
} }
fn check_opaque_type_parameter_valid(
tcx: TyCtxt<'_>,
opaque_type_key: OpaqueTypeKey<'_>,
origin: OpaqueTyOrigin,
span: Span,
) -> bool {
match origin {
// No need to check return position impl trait (RPIT)
// because for type and const parameters they are correct
// by construction: we convert
//
// fn foo<P0..Pn>() -> impl Trait
//
// into
//
// type Foo<P0...Pn>
// fn foo<P0..Pn>() -> Foo<P0...Pn>.
//
// For lifetime parameters we convert
//
// fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
//
// into
//
// type foo::<'p0..'pn>::Foo<'q0..'qm>
// fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
//
// which would error here on all of the `'static` args.
OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true,
// Check these
OpaqueTyOrigin::TyAlias => {}
}
let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default();
for (i, arg) in opaque_type_key.substs.iter().enumerate() {
let arg_is_param = match arg.unpack() {
GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
GenericArgKind::Lifetime(lt) if lt.is_static() => {
tcx.sess
.struct_span_err(span, "non-defining opaque type use in defining scope")
.span_label(
tcx.def_span(opaque_generics.param_at(i, tcx).def_id),
"cannot use static lifetime; use a bound lifetime \
instead or remove the lifetime parameter from the \
opaque type",
)
.emit();
return false;
}
GenericArgKind::Lifetime(lt) => {
matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
}
GenericArgKind::Const(ct) => matches!(ct.val(), ty::ConstKind::Param(_)),
};
if arg_is_param {
seen_params.entry(arg).or_default().push(i);
} else {
// Prevent `fn foo() -> Foo<u32>` from being defining.
let opaque_param = opaque_generics.param_at(i, tcx);
tcx.sess
.struct_span_err(span, "non-defining opaque type use in defining scope")
.span_note(
tcx.def_span(opaque_param.def_id),
&format!(
"used non-generic {} `{}` for generic parameter",
opaque_param.kind.descr(),
arg,
),
)
.emit();
return false;
}
}
for (_, indices) in seen_params {
if indices.len() > 1 {
let descr = opaque_generics.param_at(indices[0], tcx).kind.descr();
let spans: Vec<_> = indices
.into_iter()
.map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
.collect();
tcx.sess
.struct_span_err(span, "non-defining opaque type use in defining scope")
.span_note(spans, &format!("{} used multiple times", descr))
.emit();
return false;
}
}
true
}
struct ReverseMapper<'tcx> { struct ReverseMapper<'tcx> {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,

View file

@ -15,7 +15,6 @@ type TwoConsts<const X: usize, const Y: usize> = impl Debug;
fn one_ty<T: Debug>(t: T) -> TwoTys<T, T> { fn one_ty<T: Debug>(t: T) -> TwoTys<T, T> {
t t
//~^ ERROR non-defining opaque type use in defining scope //~^ ERROR non-defining opaque type use in defining scope
//~| ERROR `U` doesn't implement `Debug`
} }
fn one_lifetime<'a>(t: &'a u32) -> TwoLifetimes<'a, 'a> { fn one_lifetime<'a>(t: &'a u32) -> TwoLifetimes<'a, 'a> {

View file

@ -1,14 +1,3 @@
error[E0277]: `U` doesn't implement `Debug`
--> $DIR/generic_duplicate_param_use.rs:16:5
|
LL | t
| ^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
help: consider restricting type parameter `U`
|
LL | type TwoTys<T, U: std::fmt::Debug> = impl Debug;
| +++++++++++++++++
error: non-defining opaque type use in defining scope error: non-defining opaque type use in defining scope
--> $DIR/generic_duplicate_param_use.rs:16:5 --> $DIR/generic_duplicate_param_use.rs:16:5
| |
@ -22,7 +11,7 @@ LL | type TwoTys<T, U> = impl Debug;
| ^ ^ | ^ ^
error: non-defining opaque type use in defining scope error: non-defining opaque type use in defining scope
--> $DIR/generic_duplicate_param_use.rs:22:5 --> $DIR/generic_duplicate_param_use.rs:21:5
| |
LL | t LL | t
| ^ | ^
@ -34,7 +23,7 @@ LL | type TwoLifetimes<'a, 'b> = impl Debug;
| ^^ ^^ | ^^ ^^
error: non-defining opaque type use in defining scope error: non-defining opaque type use in defining scope
--> $DIR/generic_duplicate_param_use.rs:27:5 --> $DIR/generic_duplicate_param_use.rs:26:5
| |
LL | t LL | t
| ^ | ^
@ -45,6 +34,5 @@ note: constant used multiple times
LL | type TwoConsts<const X: usize, const Y: usize> = impl Debug; LL | type TwoConsts<const X: usize, const Y: usize> = impl Debug;
| ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^
error: aborting due to 4 previous errors error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0277`.

View file

@ -19,14 +19,6 @@ where
fn iter_bits(self, n: u8) -> Self::BitsIter { fn iter_bits(self, n: u8) -> Self::BitsIter {
(0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap()) (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
//~^ ERROR non-defining opaque type use in defining scope //~^ ERROR non-defining opaque type use in defining scope
//~| ERROR type mismatch resolving
//~| ERROR type mismatch resolving `<T as TryInto<u8>>::Error == E`
//~| ERROR no implementation for `T >> T`
//~| ERROR no implementation for `T & T`
//~| ERROR the trait bound `T: From<u8>`
//~| ERROR the trait bound `T: Copy` is not satisfied
//~| ERROR `E` doesn't implement `Debug`
//~| ERROR the trait bound `u8: From<T>` is not satisfied
} }
} }

View file

@ -1,132 +1,3 @@
error[E0271]: type mismatch resolving `<[closure@$DIR/issue-60564.rs:20:28: 20:100] as FnOnce<(u8,)>>::Output == I`
--> $DIR/issue-60564.rs:20:9
|
LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>;
| - this type parameter
...
LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found type parameter `I`
|
= note: expected type `u8`
found type parameter `I`
= note: required because of the requirements on the impl of `Iterator` for `Map<Rev<std::ops::Range<u8>>, [closure@$DIR/issue-60564.rs:20:28: 20:100]>`
error[E0271]: type mismatch resolving `<T as TryInto<u8>>::Error == E`
--> $DIR/issue-60564.rs:20:9
|
LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>;
| - this type parameter
...
LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `E`, found enum `Infallible`
|
= note: expected type parameter `E`
found enum `Infallible`
note: required by a bound in `<T as IterBits>`
--> $DIR/issue-60564.rs:15:37
|
LL | + std::convert::TryInto<u8, Error = E>,
| ^^^^^^^^^ required by this bound in `<T as IterBits>`
error[E0277]: no implementation for `T >> T`
--> $DIR/issue-60564.rs:20:9
|
LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T >> T`
|
note: required by a bound in `<T as IterBits>`
--> $DIR/issue-60564.rs:12:8
|
LL | T: std::ops::Shr<Output = T>
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<T as IterBits>`
help: consider restricting type parameter `T`
|
LL | type IterBitsIter<T: std::ops::Shr, E, I> = impl std::iter::Iterator<Item = I>;
| +++++++++++++++
error[E0277]: no implementation for `T & T`
--> $DIR/issue-60564.rs:20:9
|
LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T & T`
|
note: required by a bound in `<T as IterBits>`
--> $DIR/issue-60564.rs:13:11
|
LL | + std::ops::BitAnd<T, Output = T>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<T as IterBits>`
help: consider restricting type parameter `T`
|
LL | type IterBitsIter<T: std::ops::BitAnd, E, I> = impl std::iter::Iterator<Item = I>;
| ++++++++++++++++++
error[E0277]: the trait bound `T: From<u8>` is not satisfied
--> $DIR/issue-60564.rs:20:9
|
LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<u8>` is not implemented for `T`
|
note: required by a bound in `<T as IterBits>`
--> $DIR/issue-60564.rs:14:11
|
LL | + std::convert::From<u8>
| ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<T as IterBits>`
help: consider restricting type parameter `T`
|
LL | type IterBitsIter<T: std::convert::From<u8>, E, I> = impl std::iter::Iterator<Item = I>;
| ++++++++++++++++++++++++
error[E0277]: the trait bound `T: Copy` is not satisfied
--> $DIR/issue-60564.rs:20:9
|
LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
|
note: required by a bound in `<T as IterBits>`
--> $DIR/issue-60564.rs:10:9
|
LL | impl<T: Copy, E> IterBits for T
| ^^^^ required by this bound in `<T as IterBits>`
help: consider restricting type parameter `T`
|
LL | type IterBitsIter<T: std::marker::Copy, E, I> = impl std::iter::Iterator<Item = I>;
| +++++++++++++++++++
error[E0277]: `E` doesn't implement `Debug`
--> $DIR/issue-60564.rs:20:9
|
LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `E` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
note: required by a bound in `<T as IterBits>`
--> $DIR/issue-60564.rs:16:8
|
LL | E: std::fmt::Debug,
| ^^^^^^^^^^^^^^^ required by this bound in `<T as IterBits>`
help: consider restricting type parameter `E`
|
LL | type IterBitsIter<T, E: std::fmt::Debug, I> = impl std::iter::Iterator<Item = I>;
| +++++++++++++++++
error[E0277]: the trait bound `u8: From<T>` is not satisfied
--> $DIR/issue-60564.rs:20:9
|
LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<T>` is not implemented for `u8`
|
= note: required because of the requirements on the impl of `Into<u8>` for `T`
= note: required because of the requirements on the impl of `TryFrom<T>` for `u8`
= note: required because of the requirements on the impl of `TryInto<u8>` for `T`
note: required by a bound in `<T as IterBits>`
--> $DIR/issue-60564.rs:15:11
|
LL | + std::convert::TryInto<u8, Error = E>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<T as IterBits>`
help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
|
LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I> where u8: From<T>;
| +++++++++++++++++
error: non-defining opaque type use in defining scope error: non-defining opaque type use in defining scope
--> $DIR/issue-60564.rs:20:9 --> $DIR/issue-60564.rs:20:9
| |
@ -139,7 +10,5 @@ note: used non-generic type `u8` for generic parameter
LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>; LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>;
| ^ | ^
error: aborting due to 9 previous errors error: aborting due to previous error
Some errors have detailed explanations: E0271, E0277.
For more information about an error, try `rustc --explain E0271`.

View file

@ -8,7 +8,6 @@ type Alias<'a, U> = impl Trait<U>;
fn f<'a>() -> Alias<'a, ()> {} fn f<'a>() -> Alias<'a, ()> {}
//~^ ERROR non-defining opaque type use in defining scope //~^ ERROR non-defining opaque type use in defining scope
//~| ERROR the trait bound `(): Trait<U>` is not satisfied
fn main() {} fn main() {}

View file

@ -1,14 +1,3 @@
error[E0277]: the trait bound `(): Trait<U>` is not satisfied
--> $DIR/issue-68368-non-defining-use.rs:9:29
|
LL | fn f<'a>() -> Alias<'a, ()> {}
| ^^ the trait `Trait<U>` is not implemented for `()`
|
help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
|
LL | type Alias<'a, U> = impl Trait<U> where (): Trait<U>;
| ++++++++++++++++++
error: non-defining opaque type use in defining scope error: non-defining opaque type use in defining scope
--> $DIR/issue-68368-non-defining-use.rs:9:29 --> $DIR/issue-68368-non-defining-use.rs:9:29
| |
@ -21,6 +10,5 @@ note: used non-generic type `()` for generic parameter
LL | type Alias<'a, U> = impl Trait<U>; LL | type Alias<'a, U> = impl Trait<U>;
| ^ | ^
error: aborting due to 2 previous errors error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View file

@ -19,6 +19,5 @@ type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
fn my_fun() -> Return<()> {} fn my_fun() -> Return<()> {}
//~^ ERROR non-defining opaque type use in defining scope //~^ ERROR non-defining opaque type use in defining scope
//~| ERROR non-defining opaque type use in defining scope
fn main() {} fn main() {}

View file

@ -26,18 +26,6 @@ note: used non-generic type `()` for generic parameter
LL | type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>; LL | type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
| ^ | ^
error: non-defining opaque type use in defining scope error: aborting due to 2 previous errors
--> $DIR/issue-69136-inner-lifetime-resolve-error.rs:20:27
|
LL | fn my_fun() -> Return<()> {}
| ^^
|
note: used non-generic type `()` for generic parameter
--> $DIR/issue-69136-inner-lifetime-resolve-error.rs:17:13
|
LL | type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
| ^
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0261`. For more information about this error, try `rustc --explain E0261`.