Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

52985: cause cycle err on inf trait normalization #53316

Merged
merged 1 commit into from
Aug 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 36 additions & 9 deletions src/librustc/traits/query/normalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@
//! which folds deeply, invoking the underlying
//! `normalize_projection_ty` query when it encounters projections.

use infer::{InferCtxt, InferOk};
use infer::at::At;
use mir::interpret::{GlobalId, ConstValue};
use infer::{InferCtxt, InferOk};
use mir::interpret::{ConstValue, GlobalId};
use rustc_data_structures::small_vec::SmallVec;
use traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
use traits::project::Normalized;
use ty::{self, Ty, TyCtxt};
use traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
use ty::fold::{TypeFoldable, TypeFolder};
use ty::subst::{Subst, Substs};
use ty::{self, Ty, TyCtxt};

use super::NoSolution;

Expand Down Expand Up @@ -121,9 +121,36 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx
let concrete_ty = generic_ty.subst(self.tcx(), substs);
self.anon_depth += 1;
if concrete_ty == ty {
bug!("infinite recursion generic_ty: {:#?}, substs: {:#?}, \
concrete_ty: {:#?}, ty: {:#?}", generic_ty, substs, concrete_ty,
ty);
// The type in question can only be inferred in terms of itself. This
// is likely a user code issue, not a compiler issue. Thus, we will
// induce a cycle error by calling the parent query again on the type.
//
// FIXME: Perhaps a better solution would be to have fold_ty()
// itself be a query. Then, a type fold cycle would be detected
// and reported more naturally as part of the query system, rather
// than forcing it here.
//
// FIXME: Need a better span than just one pointing to the type def.
// Should point to a defining use of the type that results in this
// un-normalizable state.
if let Some(param_env_lifted) =
self.tcx().lift_to_global(&self.param_env)
{
if let Some(ty_lifted) = self.tcx().lift_to_global(&concrete_ty) {
let span = self.tcx().def_span(def_id);
self.tcx()
.global_tcx()
.at(span)
.normalize_ty_after_erasing_regions(
param_env_lifted.and(ty_lifted),
);
self.tcx().sess.abort_if_errors();
}
}
// If a cycle error can't be emitted, indicate a NoSolution error
// and let the caller handle it.
self.error = true;
return concrete_ty;
}
let folded_ty = self.fold_ty(concrete_ty);
self.anon_depth -= 1;
Expand All @@ -149,8 +176,8 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx
let gcx = self.infcx.tcx.global_tcx();

let mut orig_values = SmallVec::new();
let c_data =
self.infcx.canonicalize_query(&self.param_env.and(*data), &mut orig_values);
let c_data = self.infcx
.canonicalize_query(&self.param_env.and(*data), &mut orig_values);
debug!("QueryNormalizer: c_data = {:#?}", c_data);
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
match gcx.normalize_projection_ty(c_data) {
Expand Down
23 changes: 23 additions & 0 deletions src/test/ui/existential_types/no_inferrable_concrete_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Issue 52985: Cause cycle error if user code provides no use case that allows an existential type
// to be inferred to a concrete type. This results in an infinite cycle during type normalization.

#![feature(existential_type)]

existential type Foo: Copy; //~ cycle detected

// make compiler happy about using 'Foo'
fn bar(x: Foo) -> Foo { x }

fn main() {
let _: Foo = std::mem::transmute(0u8);
}
11 changes: 11 additions & 0 deletions src/test/ui/existential_types/no_inferrable_concrete_type.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0391]: cycle detected when normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All }, value: Foo }`
--> $DIR/no_inferrable_concrete_type.rs:16:1
|
LL | existential type Foo: Copy; //~ cycle detected
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: ...which again requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All }, value: Foo }`, completing the cycle

error: aborting due to previous error

For more information about this error, try `rustc --explain E0391`.