Skip to content

Commit d657d1f

Browse files
committed
Disallow defaults on type GATs
1 parent c97922d commit d657d1f

File tree

3 files changed

+96
-19
lines changed

3 files changed

+96
-19
lines changed

compiler/rustc_typeck/src/collect.rs

+42-19
Original file line numberDiff line numberDiff line change
@@ -1604,6 +1604,13 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
16041604
_ => None,
16051605
};
16061606

1607+
enum Defaults {
1608+
Allowed,
1609+
// See #36887
1610+
FutureCompatDisallowed,
1611+
Deny,
1612+
}
1613+
16071614
let no_generics = hir::Generics::empty();
16081615
let ast_generics = node.generics().unwrap_or(&no_generics);
16091616
let (opt_self, allow_defaults) = match node {
@@ -1625,17 +1632,26 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
16251632
},
16261633
});
16271634

1628-
(opt_self, true)
1635+
(opt_self, Defaults::Allowed)
16291636
}
16301637
ItemKind::TyAlias(..)
16311638
| ItemKind::Enum(..)
16321639
| ItemKind::Struct(..)
16331640
| ItemKind::OpaqueTy(..)
1634-
| ItemKind::Union(..) => (None, true),
1635-
_ => (None, false),
1641+
| ItemKind::Union(..) => (None, Defaults::Allowed),
1642+
_ => (None, Defaults::FutureCompatDisallowed),
16361643
}
16371644
}
1638-
_ => (None, false),
1645+
1646+
// GATs
1647+
Node::TraitItem(item) if matches!(item.kind, TraitItemKind::Type(..)) => {
1648+
(None, Defaults::Deny)
1649+
}
1650+
Node::ImplItem(item) if matches!(item.kind, ImplItemKind::TyAlias(..)) => {
1651+
(None, Defaults::Deny)
1652+
}
1653+
1654+
_ => (None, Defaults::FutureCompatDisallowed),
16391655
};
16401656

16411657
let has_self = opt_self.is_some();
@@ -1668,23 +1684,30 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
16681684
let type_start = own_start - has_self as u32 + params.len() as u32;
16691685
let mut i = 0;
16701686

1687+
const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \
1688+
`struct`, `enum`, `type`, or `trait` definitions";
1689+
16711690
params.extend(ast_generics.params.iter().filter_map(|param| match param.kind {
16721691
GenericParamKind::Lifetime { .. } => None,
16731692
GenericParamKind::Type { ref default, synthetic, .. } => {
1674-
if !allow_defaults && default.is_some() {
1675-
if !tcx.features().default_type_parameter_fallback {
1676-
tcx.struct_span_lint_hir(
1677-
lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
1678-
param.hir_id,
1679-
param.span,
1680-
|lint| {
1681-
lint.build(
1682-
"defaults for type parameters are only allowed in \
1683-
`struct`, `enum`, `type`, or `trait` definitions",
1684-
)
1685-
.emit();
1686-
},
1687-
);
1693+
if default.is_some() {
1694+
match allow_defaults {
1695+
Defaults::Allowed => {}
1696+
Defaults::FutureCompatDisallowed
1697+
if tcx.features().default_type_parameter_fallback => {}
1698+
Defaults::FutureCompatDisallowed => {
1699+
tcx.struct_span_lint_hir(
1700+
lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
1701+
param.hir_id,
1702+
param.span,
1703+
|lint| {
1704+
lint.build(TYPE_DEFAULT_NOT_ALLOWED).emit();
1705+
},
1706+
);
1707+
}
1708+
Defaults::Deny => {
1709+
tcx.sess.span_err(param.span, TYPE_DEFAULT_NOT_ALLOWED);
1710+
}
16881711
}
16891712
}
16901713

@@ -1701,7 +1724,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
17011724
Some(param_def)
17021725
}
17031726
GenericParamKind::Const { default, .. } => {
1704-
if !allow_defaults && default.is_some() {
1727+
if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() {
17051728
tcx.sess.span_err(
17061729
param.span,
17071730
"defaults for const parameters are only allowed in \
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Check that we disallow GAT param defaults, even with `invalid_type_param_default` allowed
2+
3+
#![allow(invalid_type_param_default)]
4+
5+
trait Trait {
6+
type Assoc<T = u32>;
7+
//~^ defaults for type parameters are only allowed
8+
}
9+
10+
impl Trait for () {
11+
type Assoc<T = u32> = u64;
12+
//~^ defaults for type parameters are only allowed
13+
}
14+
15+
impl Trait for u32 {
16+
type Assoc<T = u32> = T;
17+
//~^ defaults for type parameters are only allowed
18+
}
19+
20+
trait Other {}
21+
impl Other for u32 {}
22+
23+
fn foo<T>()
24+
where
25+
T: Trait<Assoc = u32>,
26+
T::Assoc: Other {
27+
}
28+
29+
fn main() {
30+
// errors
31+
foo::<()>();
32+
// works
33+
foo::<u32>();
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
2+
--> $DIR/type-param-defaults.rs:6:16
3+
|
4+
LL | type Assoc<T = u32>;
5+
| ^^^^^^^
6+
7+
error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
8+
--> $DIR/type-param-defaults.rs:11:16
9+
|
10+
LL | type Assoc<T = u32> = u64;
11+
| ^^^^^^^
12+
13+
error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
14+
--> $DIR/type-param-defaults.rs:16:16
15+
|
16+
LL | type Assoc<T = u32> = T;
17+
| ^^^^^^^
18+
19+
error: aborting due to 3 previous errors
20+

0 commit comments

Comments
 (0)