Check lazy type aliases for well-formedness
This commit is contained in:
parent
2e0136a131
commit
0ca432844c
@ -246,8 +246,11 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||
// `ForeignItem`s are handled separately.
|
||||
hir::ItemKind::ForeignMod { .. } => {}
|
||||
hir::ItemKind::TyAlias(hir_ty, ..) => {
|
||||
if tcx.type_of(item.owner_id.def_id).skip_binder().has_opaque_types() {
|
||||
// Bounds are respected for `type X = impl Trait` and `type X = (impl Trait, Y);`
|
||||
if tcx.features().lazy_type_alias
|
||||
|| tcx.type_of(item.owner_id).skip_binder().has_opaque_types()
|
||||
{
|
||||
// Bounds of lazy type aliases and of eager ones that contain opaque types are respected.
|
||||
// E.g: `type X = impl Trait;`, `type X = (impl Trait, Y);`.
|
||||
check_item_type(tcx, def_id, hir_ty.span, UnsizedHandling::Allow);
|
||||
}
|
||||
}
|
||||
|
@ -1458,15 +1458,20 @@ impl TypeAliasBounds {
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
|
||||
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
|
||||
let hir::ItemKind::TyAlias(ty, type_alias_generics) = &item.kind else { return };
|
||||
if cx.tcx.type_of(item.owner_id.def_id).skip_binder().has_opaque_types() {
|
||||
// Bounds are respected for `type X = impl Trait` and `type X = (impl Trait, Y);`
|
||||
let hir::ItemKind::TyAlias(hir_ty, type_alias_generics) = &item.kind else { return };
|
||||
|
||||
if cx.tcx.features().lazy_type_alias {
|
||||
// Bounds of lazy type aliases are respected.
|
||||
return;
|
||||
}
|
||||
if cx.tcx.type_of(item.owner_id).skip_binder().has_inherent_projections() {
|
||||
// Bounds are respected for `type X = … Type::Inherent …`
|
||||
|
||||
let ty = cx.tcx.type_of(item.owner_id).skip_binder();
|
||||
if ty.has_opaque_types() || ty.has_inherent_projections() {
|
||||
// Bounds of type aliases that contain opaque types or inherent projections are respected.
|
||||
// E.g: `type X = impl Trait;`, `type X = (impl Trait, Y);`, `type X = Type::Inherent;`.
|
||||
return;
|
||||
}
|
||||
|
||||
// There must not be a where clause
|
||||
if type_alias_generics.predicates.is_empty() {
|
||||
return;
|
||||
@ -1491,7 +1496,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
|
||||
if !where_spans.is_empty() {
|
||||
let sub = (!suggested_changing_assoc_types).then(|| {
|
||||
suggested_changing_assoc_types = true;
|
||||
SuggestChangingAssocTypes { ty }
|
||||
SuggestChangingAssocTypes { ty: hir_ty }
|
||||
});
|
||||
cx.emit_spanned_lint(
|
||||
TYPE_ALIAS_BOUNDS,
|
||||
@ -1507,7 +1512,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
|
||||
let suggestion = BuiltinTypeAliasGenericBoundsSuggestion { suggestions: inline_sugg };
|
||||
let sub = (!suggested_changing_assoc_types).then(|| {
|
||||
suggested_changing_assoc_types = true;
|
||||
SuggestChangingAssocTypes { ty }
|
||||
SuggestChangingAssocTypes { ty: hir_ty }
|
||||
});
|
||||
cx.emit_spanned_lint(
|
||||
TYPE_ALIAS_BOUNDS,
|
||||
|
@ -11,7 +11,7 @@ use std::path::{Path, PathBuf};
|
||||
const ENTRY_LIMIT: usize = 900;
|
||||
// FIXME: The following limits should be reduced eventually.
|
||||
const ISSUES_ENTRY_LIMIT: usize = 1893;
|
||||
const ROOT_ENTRY_LIMIT: usize = 872;
|
||||
const ROOT_ENTRY_LIMIT: usize = 873;
|
||||
|
||||
const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
|
||||
"rs", // test source files
|
||||
|
@ -1,5 +1,5 @@
|
||||
warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/lazy-type-alias-enum-variant.rs:4:12
|
||||
--> $DIR/enum-variant.rs:4:12
|
||||
|
|
||||
LL | #![feature(lazy_type_alias)]
|
||||
| ^^^^^^^^^^^^^^^
|
14
tests/ui/lazy-type-alias/type-alias-bounds-are-enforced.rs
Normal file
14
tests/ui/lazy-type-alias/type-alias-bounds-are-enforced.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// Check that we don't issue the lint `type_alias_bounds` for
|
||||
// lazy type aliases since the bounds are indeed enforced.
|
||||
|
||||
// check-pass
|
||||
|
||||
#![feature(lazy_type_alias)]
|
||||
#![allow(incomplete_features)]
|
||||
#![deny(type_alias_bounds)]
|
||||
|
||||
use std::ops::Mul;
|
||||
|
||||
type Alias<T: Mul> = <T as Mul>::Output;
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,8 @@
|
||||
// Test that we check lazy type aliases for well-formedness.
|
||||
|
||||
#![feature(lazy_type_alias)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
type Alias<T> = <T as std::ops::Mul>::Output; //~ ERROR cannot multiply `T` by `T`
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,14 @@
|
||||
error[E0277]: cannot multiply `T` by `T`
|
||||
--> $DIR/unsatisfied-bounds-type-alias-body.rs:6:17
|
||||
|
|
||||
LL | type Alias<T> = <T as std::ops::Mul>::Output;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T * T`
|
||||
|
|
||||
help: consider restricting type parameter `T`
|
||||
|
|
||||
LL | type Alias<T: std::ops::Mul> = <T as std::ops::Mul>::Output;
|
||||
| +++++++++++++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
Loading…
x
Reference in New Issue
Block a user