Skip to content

Commit 96f62fc

Browse files
committed
Auto merge of #113201 - oli-obk:recursive_type_alias, r=estebank,compiler-errors
Permit recursive weak type aliases I saw #63097 and thought "we can do ~~better~~ funnier". So here it is. It's not useful, but it's certainly something. This may actually become feasible with lazy norm (so in 5 years (constant, not reducing over time)). r? `@estebank` cc `@GuillaumeGomez`
2 parents dc348db + 5d850e0 commit 96f62fc

9 files changed

+103
-21
lines changed

compiler/rustc_hir_analysis/src/astconv/mod.rs

+12-7
Original file line numberDiff line numberDiff line change
@@ -910,19 +910,24 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
910910
) -> Ty<'tcx> {
911911
let tcx = self.tcx();
912912
let args = self.ast_path_args_for_ty(span, did, item_segment);
913-
let ty = tcx.at(span).type_of(did);
914913

915-
if let DefKind::TyAlias { lazy } = tcx.def_kind(did)
916-
&& (lazy || ty.skip_binder().has_opaque_types())
917-
{
918-
// Type aliases referring to types that contain opaque types (but aren't just directly
919-
// referencing a single opaque type) as well as those defined in crates that have the
914+
if let DefKind::TyAlias { lazy: true } = tcx.def_kind(did) {
915+
// Type aliases defined in crates that have the
920916
// feature `lazy_type_alias` enabled get encoded as a type alias that normalization will
921917
// then actually instantiate the where bounds of.
922918
let alias_ty = tcx.mk_alias_ty(did, args);
923919
Ty::new_alias(tcx, ty::Weak, alias_ty)
924920
} else {
925-
ty.instantiate(tcx, args)
921+
let ty = tcx.at(span).type_of(did);
922+
if ty.skip_binder().has_opaque_types() {
923+
// Type aliases referring to types that contain opaque types (but aren't just directly
924+
// referencing a single opaque type) get encoded as a type alias that normalization will
925+
// then actually instantiate the where bounds of.
926+
let alias_ty = tcx.mk_alias_ty(did, args);
927+
Ty::new_alias(tcx, ty::Weak, alias_ty)
928+
} else {
929+
ty.instantiate(tcx, args)
930+
}
926931
}
927932
}
928933

compiler/rustc_trait_selection/messages.ftl

+1
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,5 @@ trait_selection_no_value_in_rustc_on_unimplemented = this attribute must have a
4040
.label = expected value here
4141
.note = eg `#[rustc_on_unimplemented(message="foo")]`
4242
43+
trait_selection_ty_alias_overflow = in case this is a recursive type alias, consider using a struct, enum, or union instead
4344
trait_selection_unable_to_construct_constant_value = unable to construct a constant value for the unevaluated constant {$unevaluated}

compiler/rustc_trait_selection/src/traits/project.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,18 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
659659
normalized_ty
660660
}
661661
ty::Weak => {
662+
let recursion_limit = self.interner().recursion_limit();
663+
if !recursion_limit.value_within_limit(self.depth) {
664+
self.selcx.infcx.err_ctxt().report_overflow_error(
665+
&ty,
666+
self.cause.span,
667+
false,
668+
|diag| {
669+
diag.note(crate::fluent_generated::trait_selection_ty_alias_overflow);
670+
},
671+
);
672+
}
673+
662674
let infcx = self.selcx.infcx;
663675
self.obligations.extend(
664676
infcx.tcx.predicates_of(data.def_id).instantiate_own(infcx.tcx, data.args).map(
@@ -678,7 +690,14 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
678690
},
679691
),
680692
);
681-
infcx.tcx.type_of(data.def_id).instantiate(infcx.tcx, data.args).fold_with(self)
693+
self.depth += 1;
694+
let res = infcx
695+
.tcx
696+
.type_of(data.def_id)
697+
.instantiate(infcx.tcx, data.args)
698+
.fold_with(self);
699+
self.depth -= 1;
700+
res
682701
}
683702

684703
ty::Inherent if !data.has_escaping_bound_vars() => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0275]: overflow evaluating the requirement `X2`
2+
--> $DIR/infinite-type-alias-mutual-recursion.rs:6:11
3+
|
4+
LL | type X1 = X2;
5+
| ^^
6+
|
7+
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead
8+
9+
error[E0275]: overflow evaluating the requirement `X3`
10+
--> $DIR/infinite-type-alias-mutual-recursion.rs:9:11
11+
|
12+
LL | type X2 = X3;
13+
| ^^
14+
|
15+
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead
16+
17+
error[E0275]: overflow evaluating the requirement `X1`
18+
--> $DIR/infinite-type-alias-mutual-recursion.rs:11:11
19+
|
20+
LL | type X3 = X1;
21+
| ^^
22+
|
23+
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead
24+
25+
error: aborting due to 3 previous errors
26+
27+
For more information about this error, try `rustc --explain E0275`.

tests/ui/infinite/infinite-type-alias-mutual-recursion.stderr renamed to tests/ui/infinite/infinite-type-alias-mutual-recursion.gated.stderr

+8-7
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
error[E0391]: cycle detected when expanding type alias `X1`
2-
--> $DIR/infinite-type-alias-mutual-recursion.rs:1:11
2+
--> $DIR/infinite-type-alias-mutual-recursion.rs:6:11
33
|
44
LL | type X1 = X2;
55
| ^^
66
|
77
note: ...which requires expanding type alias `X2`...
8-
--> $DIR/infinite-type-alias-mutual-recursion.rs:3:11
8+
--> $DIR/infinite-type-alias-mutual-recursion.rs:9:11
99
|
1010
LL | type X2 = X3;
1111
| ^^
1212
note: ...which requires expanding type alias `X3`...
13-
--> $DIR/infinite-type-alias-mutual-recursion.rs:4:11
13+
--> $DIR/infinite-type-alias-mutual-recursion.rs:11:11
1414
|
1515
LL | type X3 = X1;
1616
| ^^
@@ -19,12 +19,13 @@ LL | type X3 = X1;
1919
= help: consider using a struct, enum, or union instead to break the cycle
2020
= help: see <https://doc.rust-lang.org/reference/types.html#recursive-types> for more information
2121
note: cycle used when collecting item types in top-level module
22-
--> $DIR/infinite-type-alias-mutual-recursion.rs:1:1
22+
--> $DIR/infinite-type-alias-mutual-recursion.rs:3:1
2323
|
24-
LL | / type X1 = X2;
24+
LL | / #![cfg_attr(feature, feature(lazy_type_alias))]
25+
LL | | #![allow(incomplete_features)]
2526
LL | |
26-
LL | | type X2 = X3;
27-
LL | | type X3 = X1;
27+
LL | | type X1 = X2;
28+
... |
2829
LL | |
2930
LL | | fn main() {}
3031
| |____________^
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
1+
// revisions: feature gated
2+
3+
#![cfg_attr(feature, feature(lazy_type_alias))]
4+
#![allow(incomplete_features)]
5+
16
type X1 = X2;
2-
//~^ ERROR cycle detected when expanding type alias `X1`
7+
//[gated]~^ ERROR cycle detected when expanding type alias `X1`
8+
//[feature]~^^ ERROR: overflow evaluating the requirement `X2`
39
type X2 = X3;
10+
//[feature]~^ ERROR: overflow evaluating the requirement `X3`
411
type X3 = X1;
12+
//[feature]~^ ERROR: overflow evaluating the requirement `X1`
513

614
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0275]: overflow evaluating the requirement `X`
2+
--> $DIR/infinite-vec-type-recursion.rs:6:10
3+
|
4+
LL | type X = Vec<X>;
5+
| ^^^^^^
6+
|
7+
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0275`.

tests/ui/infinite/infinite-vec-type-recursion.stderr renamed to tests/ui/infinite/infinite-vec-type-recursion.gated.stderr

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0391]: cycle detected when expanding type alias `X`
2-
--> $DIR/infinite-vec-type-recursion.rs:1:14
2+
--> $DIR/infinite-vec-type-recursion.rs:6:14
33
|
44
LL | type X = Vec<X>;
55
| ^
@@ -9,11 +9,14 @@ LL | type X = Vec<X>;
99
= help: consider using a struct, enum, or union instead to break the cycle
1010
= help: see <https://doc.rust-lang.org/reference/types.html#recursive-types> for more information
1111
note: cycle used when collecting item types in top-level module
12-
--> $DIR/infinite-vec-type-recursion.rs:1:1
12+
--> $DIR/infinite-vec-type-recursion.rs:3:1
1313
|
14-
LL | / type X = Vec<X>;
15-
LL | |
14+
LL | / #![cfg_attr(feature, feature(lazy_type_alias))]
15+
LL | | #![allow(incomplete_features)]
1616
LL | |
17+
LL | | type X = Vec<X>;
18+
... |
19+
LL | | #[rustfmt::skip]
1720
LL | | fn main() { let b: X = Vec::new(); }
1821
| |____________________________________^
1922
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1+
// revisions: feature gated
2+
3+
#![cfg_attr(feature, feature(lazy_type_alias))]
4+
#![allow(incomplete_features)]
5+
16
type X = Vec<X>;
2-
//~^ ERROR cycle detected
7+
//[gated]~^ ERROR cycle detected
8+
//[feature]~^^ ERROR: overflow evaluating the requirement `X`
39

10+
#[rustfmt::skip]
411
fn main() { let b: X = Vec::new(); }

0 commit comments

Comments
 (0)