Disallow defaults on type GATs
This commit is contained in:
parent
c97922dca5
commit
d657d1f4a1
@ -1604,6 +1604,13 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
|
||||
_ => None,
|
||||
};
|
||||
|
||||
enum Defaults {
|
||||
Allowed,
|
||||
// See #36887
|
||||
FutureCompatDisallowed,
|
||||
Deny,
|
||||
}
|
||||
|
||||
let no_generics = hir::Generics::empty();
|
||||
let ast_generics = node.generics().unwrap_or(&no_generics);
|
||||
let (opt_self, allow_defaults) = match node {
|
||||
@ -1625,17 +1632,26 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
|
||||
},
|
||||
});
|
||||
|
||||
(opt_self, true)
|
||||
(opt_self, Defaults::Allowed)
|
||||
}
|
||||
ItemKind::TyAlias(..)
|
||||
| ItemKind::Enum(..)
|
||||
| ItemKind::Struct(..)
|
||||
| ItemKind::OpaqueTy(..)
|
||||
| ItemKind::Union(..) => (None, true),
|
||||
_ => (None, false),
|
||||
| ItemKind::Union(..) => (None, Defaults::Allowed),
|
||||
_ => (None, Defaults::FutureCompatDisallowed),
|
||||
}
|
||||
}
|
||||
_ => (None, false),
|
||||
|
||||
// GATs
|
||||
Node::TraitItem(item) if matches!(item.kind, TraitItemKind::Type(..)) => {
|
||||
(None, Defaults::Deny)
|
||||
}
|
||||
Node::ImplItem(item) if matches!(item.kind, ImplItemKind::TyAlias(..)) => {
|
||||
(None, Defaults::Deny)
|
||||
}
|
||||
|
||||
_ => (None, Defaults::FutureCompatDisallowed),
|
||||
};
|
||||
|
||||
let has_self = opt_self.is_some();
|
||||
@ -1668,23 +1684,30 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
|
||||
let type_start = own_start - has_self as u32 + params.len() as u32;
|
||||
let mut i = 0;
|
||||
|
||||
const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \
|
||||
`struct`, `enum`, `type`, or `trait` definitions";
|
||||
|
||||
params.extend(ast_generics.params.iter().filter_map(|param| match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => None,
|
||||
GenericParamKind::Type { ref default, synthetic, .. } => {
|
||||
if !allow_defaults && default.is_some() {
|
||||
if !tcx.features().default_type_parameter_fallback {
|
||||
tcx.struct_span_lint_hir(
|
||||
lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
|
||||
param.hir_id,
|
||||
param.span,
|
||||
|lint| {
|
||||
lint.build(
|
||||
"defaults for type parameters are only allowed in \
|
||||
`struct`, `enum`, `type`, or `trait` definitions",
|
||||
)
|
||||
.emit();
|
||||
},
|
||||
);
|
||||
if default.is_some() {
|
||||
match allow_defaults {
|
||||
Defaults::Allowed => {}
|
||||
Defaults::FutureCompatDisallowed
|
||||
if tcx.features().default_type_parameter_fallback => {}
|
||||
Defaults::FutureCompatDisallowed => {
|
||||
tcx.struct_span_lint_hir(
|
||||
lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
|
||||
param.hir_id,
|
||||
param.span,
|
||||
|lint| {
|
||||
lint.build(TYPE_DEFAULT_NOT_ALLOWED).emit();
|
||||
},
|
||||
);
|
||||
}
|
||||
Defaults::Deny => {
|
||||
tcx.sess.span_err(param.span, TYPE_DEFAULT_NOT_ALLOWED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1701,7 +1724,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
|
||||
Some(param_def)
|
||||
}
|
||||
GenericParamKind::Const { default, .. } => {
|
||||
if !allow_defaults && default.is_some() {
|
||||
if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() {
|
||||
tcx.sess.span_err(
|
||||
param.span,
|
||||
"defaults for const parameters are only allowed in \
|
||||
|
34
src/test/ui/generic-associated-types/type-param-defaults.rs
Normal file
34
src/test/ui/generic-associated-types/type-param-defaults.rs
Normal file
@ -0,0 +1,34 @@
|
||||
// Check that we disallow GAT param defaults, even with `invalid_type_param_default` allowed
|
||||
|
||||
#![allow(invalid_type_param_default)]
|
||||
|
||||
trait Trait {
|
||||
type Assoc<T = u32>;
|
||||
//~^ defaults for type parameters are only allowed
|
||||
}
|
||||
|
||||
impl Trait for () {
|
||||
type Assoc<T = u32> = u64;
|
||||
//~^ defaults for type parameters are only allowed
|
||||
}
|
||||
|
||||
impl Trait for u32 {
|
||||
type Assoc<T = u32> = T;
|
||||
//~^ defaults for type parameters are only allowed
|
||||
}
|
||||
|
||||
trait Other {}
|
||||
impl Other for u32 {}
|
||||
|
||||
fn foo<T>()
|
||||
where
|
||||
T: Trait<Assoc = u32>,
|
||||
T::Assoc: Other {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// errors
|
||||
foo::<()>();
|
||||
// works
|
||||
foo::<u32>();
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
|
||||
--> $DIR/type-param-defaults.rs:6:16
|
||||
|
|
||||
LL | type Assoc<T = u32>;
|
||||
| ^^^^^^^
|
||||
|
||||
error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
|
||||
--> $DIR/type-param-defaults.rs:11:16
|
||||
|
|
||||
LL | type Assoc<T = u32> = u64;
|
||||
| ^^^^^^^
|
||||
|
||||
error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
|
||||
--> $DIR/type-param-defaults.rs:16:16
|
||||
|
|
||||
LL | type Assoc<T = u32> = T;
|
||||
| ^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
Loading…
x
Reference in New Issue
Block a user