Skip to content

Commit d01ed8a

Browse files
committed
Auto merge of #30676 - nikomatsakis:issue-29857, r=arielb1
This is an alternative to #29954 for fixing #29857 that seems to me to be more inline with the general strategy around `TyError`. It also includes the fix for #30589 -- in fact, just the minimal change of making `ty_is_local` tolerate `TyError` avoids the ICE, but you get a lot of duplicate error reports, so in the case where the impl's trait reference already includes `TyError`, we just ignore the impl altogether. cc @arielb1 @sanxiyn Fixes #29857. Fixes #30589.
2 parents 5cf69aa + b0f6a47 commit d01ed8a

19 files changed

+271
-52
lines changed

src/librustc/middle/traits/coherence.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@ fn overlap<'cx, 'tcx>(selcx: &mut SelectionContext<'cx, 'tcx>,
6363
b_def_id,
6464
util::fresh_type_vars_for_impl);
6565

66-
debug!("overlap: a_trait_ref={:?}", a_trait_ref);
66+
debug!("overlap: a_trait_ref={:?} a_obligations={:?}", a_trait_ref, a_obligations);
6767

68-
debug!("overlap: b_trait_ref={:?}", b_trait_ref);
68+
debug!("overlap: b_trait_ref={:?} b_obligations={:?}", b_trait_ref, b_obligations);
6969

7070
// Do `a` and `b` unify? If not, no overlap.
7171
if let Err(_) = infer::mk_eq_trait_refs(selcx.infcx(),
@@ -330,8 +330,11 @@ fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>,
330330
tt.principal_def_id().is_local()
331331
}
332332

333-
ty::TyClosure(..) |
334333
ty::TyError => {
334+
true
335+
}
336+
337+
ty::TyClosure(..) => {
335338
tcx.sess.bug(
336339
&format!("ty_is_local invoked on unexpected type: {:?}",
337340
ty))

src/librustc/middle/traits/project.rs

+20-5
Original file line numberDiff line numberDiff line change
@@ -426,11 +426,25 @@ fn opt_normalize_projection_type<'a,'b,'tcx>(
426426
}
427427
}
428428

429-
/// in various error cases, we just set TyError and return an obligation
430-
/// that, when fulfilled, will lead to an error.
429+
/// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not
430+
/// hold. In various error cases, we cannot generate a valid
431+
/// normalized projection. Therefore, we create an inference variable
432+
/// return an associated obligation that, when fulfilled, will lead to
433+
/// an error.
431434
///
432-
/// FIXME: the TyError created here can enter the obligation we create,
433-
/// leading to error messages involving TyError.
435+
/// Note that we used to return `TyError` here, but that was quite
436+
/// dubious -- the premise was that an error would *eventually* be
437+
/// reported, when the obligation was processed. But in general once
438+
/// you see a `TyError` you are supposed to be able to assume that an
439+
/// error *has been* reported, so that you can take whatever heuristic
440+
/// paths you want to take. To make things worse, it was possible for
441+
/// cycles to arise, where you basically had a setup like `<MyType<$0>
442+
/// as Trait>::Foo == $0`. Here, normalizing `<MyType<$0> as
443+
/// Trait>::Foo> to `[type error]` would lead to an obligation of
444+
/// `<MyType<[type error]> as Trait>::Foo`. We are supposed to report
445+
/// an error for this obligation, but we legitimately should not,
446+
/// because it contains `[type error]`. Yuck! (See issue #29857 for
447+
/// one case where this arose.)
434448
fn normalize_to_error<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
435449
projection_ty: ty::ProjectionTy<'tcx>,
436450
cause: ObligationCause<'tcx>,
@@ -441,8 +455,9 @@ fn normalize_to_error<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
441455
let trait_obligation = Obligation { cause: cause,
442456
recursion_depth: depth,
443457
predicate: trait_ref.to_predicate() };
458+
let new_value = selcx.infcx().next_ty_var();
444459
Normalized {
445-
value: selcx.tcx().types.err,
460+
value: new_value,
446461
obligations: vec!(trait_obligation)
447462
}
448463
}

src/librustc/middle/traits/select.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,6 @@ enum SelectionCandidate<'tcx> {
210210
BuiltinObjectCandidate,
211211

212212
BuiltinUnsizeCandidate,
213-
214-
ErrorCandidate,
215213
}
216214

217215
struct SelectionCandidateSet<'tcx> {
@@ -753,8 +751,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
753751
stack: &TraitObligationStack<'o, 'tcx>)
754752
-> SelectionResult<'tcx, SelectionCandidate<'tcx>>
755753
{
756-
if stack.obligation.predicate.0.self_ty().references_error() {
757-
return Ok(Some(ErrorCandidate));
754+
if stack.obligation.predicate.references_error() {
755+
// If we encounter a `TyError`, we generally prefer the
756+
// most "optimistic" result in response -- that is, the
757+
// one least likely to report downstream errors. But
758+
// because this routine is shared by coherence and by
759+
// trait selection, there isn't an obvious "right" choice
760+
// here in that respect, so we opt to just return
761+
// ambiguity and let the upstream clients sort it out.
762+
return Ok(None);
758763
}
759764

760765
if !self.is_knowable(stack) {
@@ -1587,7 +1592,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15871592
true
15881593
},
15891594
&ParamCandidate(..) => false,
1590-
&ErrorCandidate => false // propagate errors
15911595
},
15921596
_ => false
15931597
}
@@ -1998,10 +2002,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
19982002
try!(self.confirm_builtin_candidate(obligation, builtin_bound))))
19992003
}
20002004

2001-
ErrorCandidate => {
2002-
Ok(VtableBuiltin(VtableBuiltinData { nested: vec![] }))
2003-
}
2004-
20052005
ParamCandidate(param) => {
20062006
let obligations = self.confirm_param_candidate(obligation, param);
20072007
Ok(VtableParam(obligations))

src/librustc_typeck/check/coercion.rs

+27-27
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ use middle::ty::adjustment::{AutoAdjustment, AutoDerefRef, AdjustDerefRef};
6969
use middle::ty::adjustment::{AutoPtr, AutoUnsafe, AdjustReifyFnPointer};
7070
use middle::ty::adjustment::{AdjustUnsafeFnPointer};
7171
use middle::ty::{self, LvaluePreference, TypeAndMut, Ty};
72+
use middle::ty::fold::TypeFoldable;
7273
use middle::ty::error::TypeError;
7374
use middle::ty::relate::RelateResult;
7475
use util::common::indent;
@@ -110,10 +111,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
110111
a,
111112
b);
112113

114+
let a = self.fcx.infcx().shallow_resolve(a);
115+
116+
// Just ignore error types.
117+
if a.references_error() || b.references_error() {
118+
return Ok(None);
119+
}
120+
113121
// Consider coercing the subtype to a DST
114-
let unsize = self.unpack_actual_value(a, |a| {
115-
self.coerce_unsized(a, b)
116-
});
122+
let unsize = self.coerce_unsized(a, b);
117123
if unsize.is_ok() {
118124
return unsize;
119125
}
@@ -124,39 +130,33 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
124130
// See above for details.
125131
match b.sty {
126132
ty::TyRawPtr(mt_b) => {
127-
return self.unpack_actual_value(a, |a| {
128-
self.coerce_unsafe_ptr(a, b, mt_b.mutbl)
129-
});
133+
return self.coerce_unsafe_ptr(a, b, mt_b.mutbl);
130134
}
131135

132136
ty::TyRef(_, mt_b) => {
133-
return self.unpack_actual_value(a, |a| {
134-
self.coerce_borrowed_pointer(expr_a, a, b, mt_b.mutbl)
135-
});
137+
return self.coerce_borrowed_pointer(expr_a, a, b, mt_b.mutbl);
136138
}
137139

138140
_ => {}
139141
}
140142

141-
self.unpack_actual_value(a, |a| {
142-
match a.sty {
143-
ty::TyBareFn(Some(_), a_f) => {
144-
// Function items are coercible to any closure
145-
// type; function pointers are not (that would
146-
// require double indirection).
147-
self.coerce_from_fn_item(a, a_f, b)
148-
}
149-
ty::TyBareFn(None, a_f) => {
150-
// We permit coercion of fn pointers to drop the
151-
// unsafe qualifier.
152-
self.coerce_from_fn_pointer(a, a_f, b)
153-
}
154-
_ => {
155-
// Otherwise, just use subtyping rules.
156-
self.subtype(a, b)
157-
}
143+
match a.sty {
144+
ty::TyBareFn(Some(_), a_f) => {
145+
// Function items are coercible to any closure
146+
// type; function pointers are not (that would
147+
// require double indirection).
148+
self.coerce_from_fn_item(a, a_f, b)
158149
}
159-
})
150+
ty::TyBareFn(None, a_f) => {
151+
// We permit coercion of fn pointers to drop the
152+
// unsafe qualifier.
153+
self.coerce_from_fn_pointer(a, a_f, b)
154+
}
155+
_ => {
156+
// Otherwise, just use subtyping rules.
157+
self.subtype(a, b)
158+
}
159+
}
160160
}
161161

162162
/// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.

src/librustc_typeck/check/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1038,6 +1038,9 @@ fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
10381038
t_cast: Ty<'tcx>,
10391039
t_expr: Ty<'tcx>,
10401040
id: ast::NodeId) {
1041+
if t_cast.references_error() || t_expr.references_error() {
1042+
return;
1043+
}
10411044
let tstr = fcx.infcx().ty_to_string(t_cast);
10421045
let mut err = fcx.type_error_struct(span, |actual| {
10431046
format!("cast to unsized type: `{}` as `{}`", actual, tstr)
@@ -3511,9 +3514,10 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
35113514
let t_cast = structurally_resolved_type(fcx, expr.span, t_cast);
35123515
check_expr_with_expectation(fcx, e, ExpectCastableToType(t_cast));
35133516
let t_expr = fcx.expr_ty(e);
3517+
let t_cast = fcx.infcx().resolve_type_vars_if_possible(&t_cast);
35143518

35153519
// Eagerly check for some obvious errors.
3516-
if t_expr.references_error() {
3520+
if t_expr.references_error() || t_cast.references_error() {
35173521
fcx.write_error(id);
35183522
} else if !fcx.type_is_known_to_be_sized(t_cast, expr.span) {
35193523
report_cast_to_unsized_type(fcx, expr.span, t.span, e.span, t_cast, t_expr, id);

src/librustc_typeck/coherence/mod.rs

+12
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,23 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
149149
trait_ref,
150150
item.name);
151151

152+
// Skip impls where one of the self type is an error type.
153+
// This occurs with e.g. resolve failures (#30589).
154+
if trait_ref.references_error() {
155+
return;
156+
}
157+
152158
enforce_trait_manually_implementable(self.crate_context.tcx,
153159
item.span,
154160
trait_ref.def_id);
155161
self.add_trait_impl(trait_ref, impl_did);
156162
} else {
163+
// Skip inherent impls where the self type is an error
164+
// type. This occurs with e.g. resolve failures (#30589).
165+
if self_type.ty.references_error() {
166+
return;
167+
}
168+
157169
// Add the implementation to the mapping from implementation to base
158170
// type def ID, if there is a base type for this implementation and
159171
// the implementation does not have any associated traits.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright 2016 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+
#![feature(rustc_attrs)]
12+
13+
// Here we expect a coherence conflict because, even though `i32` does
14+
// not implement `Iterator`, we cannot rely on that negative reasoning
15+
// due to the orphan rules. Therefore, `A::Item` may yet turn out to
16+
// be `i32`.
17+
18+
pub trait Foo<P> {}
19+
20+
pub trait Bar {
21+
type Output: 'static;
22+
}
23+
24+
impl Foo<i32> for i32 { } //~ ERROR E0119
25+
26+
impl<A:Iterator> Foo<A::Item> for A { }
27+
28+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2016 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+
// Coherence error results because we do not know whether `T: Foo<P>` or not
12+
// for the second impl.
13+
14+
use std::marker::PhantomData;
15+
16+
pub trait Foo<P> {}
17+
18+
impl <P, T: Foo<P>> Foo<P> for Option<T> {} //~ ERROR E0119
19+
20+
impl<T, U> Foo<T> for Option<U> { }
21+
22+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2016 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+
use std::marker::PhantomData;
12+
13+
pub trait Foo<P> {}
14+
15+
pub trait Bar {
16+
type Output: 'static;
17+
}
18+
19+
impl Foo<i32> for i32 { } //~ ERROR E0119
20+
21+
impl<A:Bar> Foo<A::Output> for A { }
22+
23+
impl Bar for i32 {
24+
type Output = i32;
25+
}
26+
27+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2016 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+
#![feature(rustc_attrs)]
12+
#![allow(dead_code)]
13+
14+
// Here we do not get a coherence conflict because `Baz: Iterator`
15+
// does not hold and (due to the orphan rules), we can rely on that.
16+
17+
pub trait Foo<P> {}
18+
19+
pub trait Bar {
20+
type Output: 'static;
21+
}
22+
23+
struct Baz;
24+
impl Foo<i32> for Baz { }
25+
26+
impl<A:Iterator> Foo<A::Item> for A { }
27+
28+
#[rustc_error]
29+
fn main() {} //~ ERROR compilation successful
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright 2016 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+
#![feature(rustc_attrs)]
12+
13+
pub trait Foo<P> {}
14+
15+
pub trait Bar {
16+
type Output: 'static;
17+
}
18+
19+
impl Foo<i32> for i32 { }
20+
21+
impl<A:Bar> Foo<A::Output> for A { }
22+
23+
impl Bar for i32 {
24+
type Output = u32;
25+
}
26+
27+
#[rustc_error]
28+
fn main() {} //~ ERROR compilation successful

src/test/compile-fail/const-eval-overflow-4b.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use std::{u8, u16, u32, u64, usize};
2222
const A_I8_T
2323
: [u32; (i8::MAX as i8 + 1u8) as usize]
2424
//~^ ERROR mismatched types
25-
//~| the trait `core::ops::Add<u8>` is not implemented for the type `i8`
25+
//~| ERROR the trait `core::ops::Add<u8>` is not implemented for the type `i8`
2626
= [0; (i8::MAX as usize) + 1];
2727

2828
fn main() {

src/test/compile-fail/issue-19692.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ struct Homura;
1212

1313
fn akemi(homura: Homura) {
1414
let Some(ref madoka) = Some(homura.kaname()); //~ ERROR no method named `kaname` found
15-
madoka.clone(); //~ ERROR the type of this value must be known in this context
15+
madoka.clone(); //~ ERROR the type of this value must be known
1616
}
1717

1818
fn main() { }

0 commit comments

Comments
 (0)