Disallow defaults on type GATs

This commit is contained in:
Jack Huey 2022-09-14 10:02:48 -04:00
parent c97922dca5
commit d657d1f4a1
3 changed files with 96 additions and 19 deletions

View File

@ -1604,6 +1604,13 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
_ => None, _ => None,
}; };
enum Defaults {
Allowed,
// See #36887
FutureCompatDisallowed,
Deny,
}
let no_generics = hir::Generics::empty(); let no_generics = hir::Generics::empty();
let ast_generics = node.generics().unwrap_or(&no_generics); let ast_generics = node.generics().unwrap_or(&no_generics);
let (opt_self, allow_defaults) = match node { 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::TyAlias(..)
| ItemKind::Enum(..) | ItemKind::Enum(..)
| ItemKind::Struct(..) | ItemKind::Struct(..)
| ItemKind::OpaqueTy(..) | ItemKind::OpaqueTy(..)
| ItemKind::Union(..) => (None, true), | ItemKind::Union(..) => (None, Defaults::Allowed),
_ => (None, false), _ => (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(); 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 type_start = own_start - has_self as u32 + params.len() as u32;
let mut i = 0; 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 { params.extend(ast_generics.params.iter().filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => None, GenericParamKind::Lifetime { .. } => None,
GenericParamKind::Type { ref default, synthetic, .. } => { GenericParamKind::Type { ref default, synthetic, .. } => {
if !allow_defaults && default.is_some() { if default.is_some() {
if !tcx.features().default_type_parameter_fallback { match allow_defaults {
tcx.struct_span_lint_hir( Defaults::Allowed => {}
lint::builtin::INVALID_TYPE_PARAM_DEFAULT, Defaults::FutureCompatDisallowed
param.hir_id, if tcx.features().default_type_parameter_fallback => {}
param.span, Defaults::FutureCompatDisallowed => {
|lint| { tcx.struct_span_lint_hir(
lint.build( lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
"defaults for type parameters are only allowed in \ param.hir_id,
`struct`, `enum`, `type`, or `trait` definitions", param.span,
) |lint| {
.emit(); 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) Some(param_def)
} }
GenericParamKind::Const { default, .. } => { GenericParamKind::Const { default, .. } => {
if !allow_defaults && default.is_some() { if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() {
tcx.sess.span_err( tcx.sess.span_err(
param.span, param.span,
"defaults for const parameters are only allowed in \ "defaults for const parameters are only allowed in \

View 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>();
}

View File

@ -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