Permit recursive weak type aliases

This commit is contained in:
Oli Scherer 2023-06-30 13:54:15 +00:00
parent 7659abc63d
commit 5d850e0f50
9 changed files with 104 additions and 22 deletions

View File

@ -910,19 +910,24 @@ fn ast_path_to_ty(
) -> Ty<'tcx> { ) -> Ty<'tcx> {
let tcx = self.tcx(); let tcx = self.tcx();
let args = self.ast_path_args_for_ty(span, did, item_segment); let args = self.ast_path_args_for_ty(span, did, item_segment);
let ty = tcx.at(span).type_of(did);
if let DefKind::TyAlias { lazy } = tcx.def_kind(did) if let DefKind::TyAlias { lazy: true } = tcx.def_kind(did) {
&& (lazy || ty.skip_binder().has_opaque_types()) // Type aliases defined in crates that have the
{
// Type aliases referring to types that contain opaque types (but aren't just directly
// referencing a single opaque type) as well as those defined in crates that have the
// feature `lazy_type_alias` enabled get encoded as a type alias that normalization will // feature `lazy_type_alias` enabled get encoded as a type alias that normalization will
// then actually instantiate the where bounds of. // then actually instantiate the where bounds of.
let alias_ty = tcx.mk_alias_ty(did, args); let alias_ty = tcx.mk_alias_ty(did, args);
Ty::new_alias(tcx, ty::Weak, alias_ty) Ty::new_alias(tcx, ty::Weak, alias_ty)
} else { } else {
ty.instantiate(tcx, args) let ty = tcx.at(span).type_of(did);
if ty.skip_binder().has_opaque_types() {
// Type aliases referring to types that contain opaque types (but aren't just directly
// referencing a single opaque type) get encoded as a type alias that normalization will
// then actually instantiate the where bounds of.
let alias_ty = tcx.mk_alias_ty(did, args);
Ty::new_alias(tcx, ty::Weak, alias_ty)
} else {
ty.instantiate(tcx, args)
}
} }
} }

View File

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

View File

@ -659,6 +659,18 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
normalized_ty normalized_ty
} }
ty::Weak => { ty::Weak => {
let recursion_limit = self.interner().recursion_limit();
if !recursion_limit.value_within_limit(self.depth) {
self.selcx.infcx.err_ctxt().report_overflow_error(
&ty,
self.cause.span,
false,
|diag| {
diag.note(crate::fluent_generated::trait_selection_ty_alias_overflow);
},
);
}
let infcx = self.selcx.infcx; let infcx = self.selcx.infcx;
self.obligations.extend( self.obligations.extend(
infcx.tcx.predicates_of(data.def_id).instantiate_own(infcx.tcx, data.args).map( infcx.tcx.predicates_of(data.def_id).instantiate_own(infcx.tcx, data.args).map(
@ -678,7 +690,14 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
}, },
), ),
); );
infcx.tcx.type_of(data.def_id).instantiate(infcx.tcx, data.args).fold_with(self) self.depth += 1;
let res = infcx
.tcx
.type_of(data.def_id)
.instantiate(infcx.tcx, data.args)
.fold_with(self);
self.depth -= 1;
res
} }
ty::Inherent if !data.has_escaping_bound_vars() => { ty::Inherent if !data.has_escaping_bound_vars() => {

View File

@ -0,0 +1,27 @@
error[E0275]: overflow evaluating the requirement `X2`
--> $DIR/infinite-type-alias-mutual-recursion.rs:6:11
|
LL | type X1 = X2;
| ^^
|
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead
error[E0275]: overflow evaluating the requirement `X3`
--> $DIR/infinite-type-alias-mutual-recursion.rs:9:11
|
LL | type X2 = X3;
| ^^
|
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead
error[E0275]: overflow evaluating the requirement `X1`
--> $DIR/infinite-type-alias-mutual-recursion.rs:11:11
|
LL | type X3 = X1;
| ^^
|
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0275`.

View File

@ -1,16 +1,16 @@
error[E0391]: cycle detected when expanding type alias `X1` error[E0391]: cycle detected when expanding type alias `X1`
--> $DIR/infinite-type-alias-mutual-recursion.rs:1:11 --> $DIR/infinite-type-alias-mutual-recursion.rs:6:11
| |
LL | type X1 = X2; LL | type X1 = X2;
| ^^ | ^^
| |
note: ...which requires expanding type alias `X2`... note: ...which requires expanding type alias `X2`...
--> $DIR/infinite-type-alias-mutual-recursion.rs:3:11 --> $DIR/infinite-type-alias-mutual-recursion.rs:9:11
| |
LL | type X2 = X3; LL | type X2 = X3;
| ^^ | ^^
note: ...which requires expanding type alias `X3`... note: ...which requires expanding type alias `X3`...
--> $DIR/infinite-type-alias-mutual-recursion.rs:4:11 --> $DIR/infinite-type-alias-mutual-recursion.rs:11:11
| |
LL | type X3 = X1; LL | type X3 = X1;
| ^^ | ^^
@ -19,12 +19,13 @@ LL | type X3 = X1;
= help: consider using a struct, enum, or union instead to break the cycle = help: consider using a struct, enum, or union instead to break the cycle
= help: see <https://doc.rust-lang.org/reference/types.html#recursive-types> for more information = help: see <https://doc.rust-lang.org/reference/types.html#recursive-types> for more information
note: cycle used when collecting item types in top-level module note: cycle used when collecting item types in top-level module
--> $DIR/infinite-type-alias-mutual-recursion.rs:1:1 --> $DIR/infinite-type-alias-mutual-recursion.rs:3:1
| |
LL | / type X1 = X2; LL | / #![cfg_attr(feature, feature(lazy_type_alias))]
LL | | #![allow(incomplete_features)]
LL | | LL | |
LL | | type X2 = X3; LL | | type X1 = X2;
LL | | type X3 = X1; ... |
LL | | LL | |
LL | | fn main() {} LL | | fn main() {}
| |____________^ | |____________^

View File

@ -1,6 +1,14 @@
// revisions: feature gated
#![cfg_attr(feature, feature(lazy_type_alias))]
#![allow(incomplete_features)]
type X1 = X2; type X1 = X2;
//~^ ERROR cycle detected when expanding type alias `X1` //[gated]~^ ERROR cycle detected when expanding type alias `X1`
//[feature]~^^ ERROR: overflow evaluating the requirement `X2`
type X2 = X3; type X2 = X3;
//[feature]~^ ERROR: overflow evaluating the requirement `X3`
type X3 = X1; type X3 = X1;
//[feature]~^ ERROR: overflow evaluating the requirement `X1`
fn main() {} fn main() {}

View File

@ -0,0 +1,11 @@
error[E0275]: overflow evaluating the requirement `X`
--> $DIR/infinite-vec-type-recursion.rs:6:10
|
LL | type X = Vec<X>;
| ^^^^^^
|
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead
error: aborting due to previous error
For more information about this error, try `rustc --explain E0275`.

View File

@ -1,5 +1,5 @@
error[E0391]: cycle detected when expanding type alias `X` error[E0391]: cycle detected when expanding type alias `X`
--> $DIR/infinite-vec-type-recursion.rs:1:14 --> $DIR/infinite-vec-type-recursion.rs:6:14
| |
LL | type X = Vec<X>; LL | type X = Vec<X>;
| ^ | ^
@ -9,11 +9,14 @@ LL | type X = Vec<X>;
= help: consider using a struct, enum, or union instead to break the cycle = help: consider using a struct, enum, or union instead to break the cycle
= help: see <https://doc.rust-lang.org/reference/types.html#recursive-types> for more information = help: see <https://doc.rust-lang.org/reference/types.html#recursive-types> for more information
note: cycle used when collecting item types in top-level module note: cycle used when collecting item types in top-level module
--> $DIR/infinite-vec-type-recursion.rs:1:1 --> $DIR/infinite-vec-type-recursion.rs:3:1
| |
LL | / type X = Vec<X>; LL | / #![cfg_attr(feature, feature(lazy_type_alias))]
LL | | LL | | #![allow(incomplete_features)]
LL | | LL | |
LL | | type X = Vec<X>;
... |
LL | | #[rustfmt::skip]
LL | | fn main() { let b: X = Vec::new(); } LL | | fn main() { let b: X = Vec::new(); }
| |____________________________________^ | |____________________________________^
= 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 = 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

View File

@ -1,4 +1,11 @@
type X = Vec<X>; // revisions: feature gated
//~^ ERROR cycle detected
#![cfg_attr(feature, feature(lazy_type_alias))]
#![allow(incomplete_features)]
type X = Vec<X>;
//[gated]~^ ERROR cycle detected
//[feature]~^^ ERROR: overflow evaluating the requirement `X`
#[rustfmt::skip]
fn main() { let b: X = Vec::new(); } fn main() { let b: X = Vec::new(); }