Skip to content

Commit f28f648

Browse files
committed
Auto merge of #53316 - tristanburgess:52895_existential_type_ICE, r=oli-obk
52985: cause cycle err on inf trait normalization Issue: #52985 - If an existential type is defined, but no user code infers the concrete type behind the existential type, normalization would infinitely recurse on this existential type which is only defined in terms of itself. - Instead of raising an inf recurse error, we cause a cycle error to help highlight that the issue is that the type is only defined in terms of itself. - Three known potential improvements: - If type folding itself was exposed as a query, used by normalization and other mechanisms, cases that would cause infinite recursion would automatically cause a cycle error. - The span for the cycle error should be improved to point to user code that fails to allow inference of the concrete type of the existential type, assuming that this error occurs because no user code can allow inference the concrete type. - A mechanism to extend the cycle error with a helpful note would be nice. Currently, the error is built and maintained by src/librustc/ty/query/plumbing, with no known way to extend the information that the error gets built with. r? @oli-obk
2 parents 3ac79c7 + 8895e3b commit f28f648

File tree

3 files changed

+70
-9
lines changed

3 files changed

+70
-9
lines changed

Diff for: src/librustc/traits/query/normalize.rs

+36-9
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@
1212
//! which folds deeply, invoking the underlying
1313
//! `normalize_projection_ty` query when it encounters projections.
1414
15-
use infer::{InferCtxt, InferOk};
1615
use infer::at::At;
17-
use mir::interpret::{GlobalId, ConstValue};
16+
use infer::{InferCtxt, InferOk};
17+
use mir::interpret::{ConstValue, GlobalId};
1818
use rustc_data_structures::small_vec::SmallVec;
19-
use traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
2019
use traits::project::Normalized;
21-
use ty::{self, Ty, TyCtxt};
20+
use traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
2221
use ty::fold::{TypeFoldable, TypeFolder};
2322
use ty::subst::{Subst, Substs};
23+
use ty::{self, Ty, TyCtxt};
2424

2525
use super::NoSolution;
2626

@@ -121,9 +121,36 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx
121121
let concrete_ty = generic_ty.subst(self.tcx(), substs);
122122
self.anon_depth += 1;
123123
if concrete_ty == ty {
124-
bug!("infinite recursion generic_ty: {:#?}, substs: {:#?}, \
125-
concrete_ty: {:#?}, ty: {:#?}", generic_ty, substs, concrete_ty,
126-
ty);
124+
// The type in question can only be inferred in terms of itself. This
125+
// is likely a user code issue, not a compiler issue. Thus, we will
126+
// induce a cycle error by calling the parent query again on the type.
127+
//
128+
// FIXME: Perhaps a better solution would be to have fold_ty()
129+
// itself be a query. Then, a type fold cycle would be detected
130+
// and reported more naturally as part of the query system, rather
131+
// than forcing it here.
132+
//
133+
// FIXME: Need a better span than just one pointing to the type def.
134+
// Should point to a defining use of the type that results in this
135+
// un-normalizable state.
136+
if let Some(param_env_lifted) =
137+
self.tcx().lift_to_global(&self.param_env)
138+
{
139+
if let Some(ty_lifted) = self.tcx().lift_to_global(&concrete_ty) {
140+
let span = self.tcx().def_span(def_id);
141+
self.tcx()
142+
.global_tcx()
143+
.at(span)
144+
.normalize_ty_after_erasing_regions(
145+
param_env_lifted.and(ty_lifted),
146+
);
147+
self.tcx().sess.abort_if_errors();
148+
}
149+
}
150+
// If a cycle error can't be emitted, indicate a NoSolution error
151+
// and let the caller handle it.
152+
self.error = true;
153+
return concrete_ty;
127154
}
128155
let folded_ty = self.fold_ty(concrete_ty);
129156
self.anon_depth -= 1;
@@ -149,8 +176,8 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx
149176
let gcx = self.infcx.tcx.global_tcx();
150177

151178
let mut orig_values = SmallVec::new();
152-
let c_data =
153-
self.infcx.canonicalize_query(&self.param_env.and(*data), &mut orig_values);
179+
let c_data = self.infcx
180+
.canonicalize_query(&self.param_env.and(*data), &mut orig_values);
154181
debug!("QueryNormalizer: c_data = {:#?}", c_data);
155182
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
156183
match gcx.normalize_projection_ty(c_data) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Issue 52985: Cause cycle error if user code provides no use case that allows an existential type
12+
// to be inferred to a concrete type. This results in an infinite cycle during type normalization.
13+
14+
#![feature(existential_type)]
15+
16+
existential type Foo: Copy; //~ cycle detected
17+
18+
// make compiler happy about using 'Foo'
19+
fn bar(x: Foo) -> Foo { x }
20+
21+
fn main() {
22+
let _: Foo = std::mem::transmute(0u8);
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0391]: cycle detected when normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All }, value: Foo }`
2+
--> $DIR/no_inferrable_concrete_type.rs:16:1
3+
|
4+
LL | existential type Foo: Copy; //~ cycle detected
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: ...which again requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All }, value: Foo }`, completing the cycle
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0391`.

0 commit comments

Comments
 (0)