Skip to content

Commit

Permalink
Disallow defaults on type GATs
Browse files Browse the repository at this point in the history
  • Loading branch information
jackh726 committed Sep 14, 2022
1 parent c97922d commit d657d1f
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 19 deletions.
61 changes: 42 additions & 19 deletions compiler/rustc_typeck/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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();
Expand Down Expand Up @@ -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);
}
}
}

Expand All @@ -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 \
Expand Down
34 changes: 34 additions & 0 deletions src/test/ui/generic-associated-types/type-param-defaults.rs
Original file line number Diff line number Diff line change
@@ -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>();
}
20 changes: 20 additions & 0 deletions src/test/ui/generic-associated-types/type-param-defaults.stderr
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit d657d1f

Please sign in to comment.