diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 668763f9bf6..7a6856fb1f4 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -910,19 +910,24 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) -> Ty<'tcx> { let tcx = self.tcx(); 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) - && (lazy || 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) as well as those defined in crates that have the + if let DefKind::TyAlias { lazy: true } = tcx.def_kind(did) { + // Type aliases defined in crates that have the // feature `lazy_type_alias` enabled 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) + 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) + } } } diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index f4c9dfa3488..2a09a7dcd89 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -40,4 +40,5 @@ trait_selection_no_value_in_rustc_on_unimplemented = this attribute must have a .label = expected value here .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} diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 06a1027e5df..b31c0e655fb 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -659,6 +659,18 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx normalized_ty } 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; self.obligations.extend( infcx.tcx.predicates_of(data.def_id).instantiate_own(infcx.tcx, data.args).map( @@ -678,7 +690,14 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, '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() => { diff --git a/tests/ui/infinite/infinite-type-alias-mutual-recursion.feature.stderr b/tests/ui/infinite/infinite-type-alias-mutual-recursion.feature.stderr new file mode 100644 index 00000000000..8b8fc46dfc5 --- /dev/null +++ b/tests/ui/infinite/infinite-type-alias-mutual-recursion.feature.stderr @@ -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`. diff --git a/tests/ui/infinite/infinite-type-alias-mutual-recursion.stderr b/tests/ui/infinite/infinite-type-alias-mutual-recursion.gated.stderr similarity index 74% rename from tests/ui/infinite/infinite-type-alias-mutual-recursion.stderr rename to tests/ui/infinite/infinite-type-alias-mutual-recursion.gated.stderr index bbdb1f70b80..ec63688fa8b 100644 --- a/tests/ui/infinite/infinite-type-alias-mutual-recursion.stderr +++ b/tests/ui/infinite/infinite-type-alias-mutual-recursion.gated.stderr @@ -1,16 +1,16 @@ 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; | ^^ | 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; | ^^ 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; | ^^ @@ -19,12 +19,13 @@ LL | type X3 = X1; = help: consider using a struct, enum, or union instead to break the cycle = help: see for more information 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 | | type X2 = X3; -LL | | type X3 = X1; +LL | | type X1 = X2; +... | LL | | LL | | fn main() {} | |____________^ diff --git a/tests/ui/infinite/infinite-type-alias-mutual-recursion.rs b/tests/ui/infinite/infinite-type-alias-mutual-recursion.rs index 5381eedcfac..90c941c634e 100644 --- a/tests/ui/infinite/infinite-type-alias-mutual-recursion.rs +++ b/tests/ui/infinite/infinite-type-alias-mutual-recursion.rs @@ -1,6 +1,14 @@ +// revisions: feature gated + +#![cfg_attr(feature, feature(lazy_type_alias))] +#![allow(incomplete_features)] + 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; +//[feature]~^ ERROR: overflow evaluating the requirement `X3` type X3 = X1; +//[feature]~^ ERROR: overflow evaluating the requirement `X1` fn main() {} diff --git a/tests/ui/infinite/infinite-vec-type-recursion.feature.stderr b/tests/ui/infinite/infinite-vec-type-recursion.feature.stderr new file mode 100644 index 00000000000..3a146215905 --- /dev/null +++ b/tests/ui/infinite/infinite-vec-type-recursion.feature.stderr @@ -0,0 +1,11 @@ +error[E0275]: overflow evaluating the requirement `X` + --> $DIR/infinite-vec-type-recursion.rs:6:10 + | +LL | type X = Vec; + | ^^^^^^ + | + = 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`. diff --git a/tests/ui/infinite/infinite-vec-type-recursion.stderr b/tests/ui/infinite/infinite-vec-type-recursion.gated.stderr similarity index 77% rename from tests/ui/infinite/infinite-vec-type-recursion.stderr rename to tests/ui/infinite/infinite-vec-type-recursion.gated.stderr index a21b033a9a9..e47d9b652fb 100644 --- a/tests/ui/infinite/infinite-vec-type-recursion.stderr +++ b/tests/ui/infinite/infinite-vec-type-recursion.gated.stderr @@ -1,5 +1,5 @@ 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; | ^ @@ -9,11 +9,14 @@ LL | type X = Vec; = help: consider using a struct, enum, or union instead to break the cycle = help: see for more information 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; -LL | | +LL | / #![cfg_attr(feature, feature(lazy_type_alias))] +LL | | #![allow(incomplete_features)] LL | | +LL | | type X = Vec; +... | +LL | | #[rustfmt::skip] 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 diff --git a/tests/ui/infinite/infinite-vec-type-recursion.rs b/tests/ui/infinite/infinite-vec-type-recursion.rs index 35681822598..71ab4a33013 100644 --- a/tests/ui/infinite/infinite-vec-type-recursion.rs +++ b/tests/ui/infinite/infinite-vec-type-recursion.rs @@ -1,4 +1,11 @@ -type X = Vec; -//~^ ERROR cycle detected +// revisions: feature gated +#![cfg_attr(feature, feature(lazy_type_alias))] +#![allow(incomplete_features)] + +type X = Vec; +//[gated]~^ ERROR cycle detected +//[feature]~^^ ERROR: overflow evaluating the requirement `X` + +#[rustfmt::skip] fn main() { let b: X = Vec::new(); }