Skip to content

Commit

Permalink
Fix unresolved inference variable ICE.
Browse files Browse the repository at this point in the history
This commit moves well-formedness check for the
`UserTypeAnnotation::Ty(..)` case from always running to only when the
code is reachable. This solves the ICE that resulted from
`src/test/ui/issue-54943-1.rs` (a minimal repro of `dropck-eyepatch`
run-pass tests that failed).

The main well-formedness check that was intended to be run despite
unreachable code still is, that being the
`UserTypeAnnotation::TypeOf(..)` case. Before this PR, the other case
wasn't being checked at all.

It is possible to fix this ICE while still always checking
well-formedness for the `UserTypeAnnotation::Ty(..)` case but that
solution will ICE in unreachable code for that case, the diff for
that change [can be found here](0).

[0]: https://gist.github.com/davidtwco/f9751ffd9c0508f7251c0f17adc3af53
  • Loading branch information
davidtwco committed Dec 30, 2018
1 parent 6092d92 commit 95c1838
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 16 deletions.
58 changes: 44 additions & 14 deletions src/librustc_mir/borrow_check/nll/type_check/mod.rs
Expand Up @@ -933,19 +933,28 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
for index in self.mir.user_type_annotations.indices() {
let (span, _) = &self.mir.user_type_annotations[index];
let type_annotation = self.instantiated_type_annotations[&index];
if let Err(terr) = self.fully_perform_op(
Locations::All(*span),
ConstraintCategory::Assignment,
self.param_env.and(type_op::ascribe_user_type::AscribeUserTypeWellFormed::new(
type_annotation,
)),
) {
span_mirbug!(
self,
type_annotation,
"bad user type annotation: {:?}",
terr,
);
match type_annotation {
// We can't check the well-formedness of a `UserTypeAnnotation::Ty` here, it will
// cause ICEs (see comment in `relate_type_and_user_type`).
UserTypeAnnotation::TypeOf(..) => {
if let Err(terr) = self.fully_perform_op(
Locations::All(*span),
ConstraintCategory::Assignment,
self.param_env.and(
type_op::ascribe_user_type::AscribeUserTypeWellFormed::new(
type_annotation,
)
),
) {
span_mirbug!(
self,
type_annotation,
"bad user type annotation: {:?}",
terr,
);
}
},
_ => {},
}
}
}
Expand Down Expand Up @@ -1079,7 +1088,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
a, v, user_ty, locations,
);

match self.instantiated_type_annotations[&user_ty.base] {
let type_annotation = self.instantiated_type_annotations[&user_ty.base];
match type_annotation {
UserTypeAnnotation::Ty(ty) => {
// The `TypeRelating` code assumes that "unresolved inference
// variables" appear in the "a" side, so flip `Contravariant`
Expand Down Expand Up @@ -1117,7 +1127,27 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
if let Ok(projected_ty) = curr_projected_ty {
let ty = projected_ty.to_ty(tcx);
self.relate_types(ty, v1, a, locations, category)?;

// We'll get an ICE if we check for well-formedness of a
// `UserTypeAnnotation::Ty` that hasn't had types related.
//
// Doing this without the types having been related will result in
// `probe_ty_var` failing in the canonicalizer - in practice, this
// results in three run-pass tests failing. You can work around that
// by keeping an vec of projections instead of annotations and performing
// the projections before storing into `instantiated_type_annotations`
// but that still fails in dead code.
self.fully_perform_op(
locations,
category,
self.param_env.and(
type_op::ascribe_user_type::AscribeUserTypeWellFormed::new(
UserTypeAnnotation::Ty(ty),
)
),
)?;
}

}
UserTypeAnnotation::TypeOf(def_id, user_substs) => {
let projs = self.infcx.tcx.intern_projs(&user_ty.projs);
Expand Down
2 changes: 1 addition & 1 deletion src/test/incremental/hashes/let_expressions.rs
Expand Up @@ -70,7 +70,7 @@ pub fn change_mutability_of_reference_type() {

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,TypeckTables,MirValidated")]
except="HirBody,TypeckTables,MirValidated,MirOptimized")]
#[rustc_clean(cfg="cfail3")]
pub fn change_mutability_of_reference_type() {
let _x: &mut u64;
Expand Down
15 changes: 15 additions & 0 deletions src/test/ui/issue-54943-1.rs
@@ -0,0 +1,15 @@
#![feature(nll)]

// This test is a minimal version of an ICE in the dropck-eyepatch tests
// found in the fix for #54943.

// compile-pass

fn foo<T>(_t: T) {
}

fn main() {
struct A<'a, B: 'a>(&'a B);
let (a1, a2): (String, A<_>) = (String::from("auto"), A(&"this"));
foo((a1, a2));
}
18 changes: 18 additions & 0 deletions src/test/ui/issue-54943-2.rs
@@ -0,0 +1,18 @@
#![feature(nll)]

// This test is a minimal version of an ICE in the dropck-eyepatch tests
// found in the fix for #54943. In particular, this test is in unreachable
// code as the initial fix for this ICE only worked if the code was reachable.

// compile-pass

fn foo<T>(_t: T) {
}

fn main() {
return;

struct A<'a, B: 'a>(&'a B);
let (a1, a2): (String, A<_>) = (String::from("auto"), A(&"this"));
foo((a1, a2));
}
Expand Up @@ -21,7 +21,7 @@ LL | fn call1<'a>(x: &'a usize) {
LL | let z: &'a & usize = &(&y);
| ----------- ^^^^ borrowed value does not live long enough
| |
| assignment requires that `y` is borrowed for `'a`
| type annotation requires that `y` is borrowed for `'a`
...
LL | }
| - `y` dropped here while still borrowed
Expand Down

0 comments on commit 95c1838

Please sign in to comment.