Skip to content

Commit

Permalink
Merge pull request #30847 from nikomatsakis/issue-29857-beta
Browse files Browse the repository at this point in the history
[beta] Backport fix for issue 29857
  • Loading branch information
brson committed Jan 12, 2016
2 parents 4dd6b09 + e5954cd commit cedaee6
Show file tree
Hide file tree
Showing 11 changed files with 115 additions and 40 deletions.
25 changes: 20 additions & 5 deletions src/librustc/middle/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,11 +426,25 @@ fn opt_normalize_projection_type<'a,'b,'tcx>(
}
}

/// in various error cases, we just set TyError and return an obligation
/// that, when fulfilled, will lead to an error.
/// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not
/// hold. In various error cases, we cannot generate a valid
/// normalized projection. Therefore, we create an inference variable
/// return an associated obligation that, when fulfilled, will lead to
/// an error.
///
/// FIXME: the TyError created here can enter the obligation we create,
/// leading to error messages involving TyError.
/// Note that we used to return `TyError` here, but that was quite
/// dubious -- the premise was that an error would *eventually* be
/// reported, when the obligation was processed. But in general once
/// you see a `TyError` you are supposed to be able to assume that an
/// error *has been* reported, so that you can take whatever heuristic
/// paths you want to take. To make things worse, it was possible for
/// cycles to arise, where you basically had a setup like `<MyType<$0>
/// as Trait>::Foo == $0`. Here, normalizing `<MyType<$0> as
/// Trait>::Foo> to `[type error]` would lead to an obligation of
/// `<MyType<[type error]> as Trait>::Foo`. We are supposed to report
/// an error for this obligation, but we legitimately should not,
/// because it contains `[type error]`. Yuck! (See issue #29857 for
/// one case where this arose.)
fn normalize_to_error<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
projection_ty: ty::ProjectionTy<'tcx>,
cause: ObligationCause<'tcx>,
Expand All @@ -441,8 +455,9 @@ fn normalize_to_error<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
let trait_obligation = Obligation { cause: cause,
recursion_depth: depth,
predicate: trait_ref.to_predicate() };
let new_value = selcx.infcx().next_ty_var();
Normalized {
value: selcx.tcx().types.err,
value: new_value,
obligations: vec!(trait_obligation)
}
}
Expand Down
55 changes: 27 additions & 28 deletions src/librustc_typeck/check/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ use middle::traits::{predicate_for_trait_def, report_selection_error};
use middle::ty::adjustment::{AutoAdjustment, AutoDerefRef, AdjustDerefRef};
use middle::ty::adjustment::{AutoPtr, AutoUnsafe, AdjustReifyFnPointer};
use middle::ty::adjustment::{AdjustUnsafeFnPointer};
use middle::ty::{self, LvaluePreference, TypeAndMut, Ty};
use middle::ty::{self, HasTypeFlags, LvaluePreference, TypeAndMut, Ty};
use middle::ty::error::TypeError;
use middle::ty::relate::RelateResult;
use util::common::indent;
Expand Down Expand Up @@ -110,10 +110,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
a,
b);

let a = self.fcx.infcx().shallow_resolve(a);

// Just ignore error types.
if a.references_error() || b.references_error() {
return Ok(None);
}

// Consider coercing the subtype to a DST
let unsize = self.unpack_actual_value(a, |a| {
self.coerce_unsized(a, b)
});
let unsize = self.coerce_unsized(a, b);
if unsize.is_ok() {
return unsize;
}
Expand All @@ -124,39 +129,33 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// See above for details.
match b.sty {
ty::TyRawPtr(mt_b) => {
return self.unpack_actual_value(a, |a| {
self.coerce_unsafe_ptr(a, b, mt_b.mutbl)
});
return self.coerce_unsafe_ptr(a, b, mt_b.mutbl);
}

ty::TyRef(_, mt_b) => {
return self.unpack_actual_value(a, |a| {
self.coerce_borrowed_pointer(expr_a, a, b, mt_b.mutbl)
});
return self.coerce_borrowed_pointer(expr_a, a, b, mt_b.mutbl);
}

_ => {}
}

self.unpack_actual_value(a, |a| {
match a.sty {
ty::TyBareFn(Some(_), a_f) => {
// Function items are coercible to any closure
// type; function pointers are not (that would
// require double indirection).
self.coerce_from_fn_item(a, a_f, b)
}
ty::TyBareFn(None, a_f) => {
// We permit coercion of fn pointers to drop the
// unsafe qualifier.
self.coerce_from_fn_pointer(a, a_f, b)
}
_ => {
// Otherwise, just use subtyping rules.
self.subtype(a, b)
}
match a.sty {
ty::TyBareFn(Some(_), a_f) => {
// Function items are coercible to any closure
// type; function pointers are not (that would
// require double indirection).
self.coerce_from_fn_item(a, a_f, b)
}
})
ty::TyBareFn(None, a_f) => {
// We permit coercion of fn pointers to drop the
// unsafe qualifier.
self.coerce_from_fn_pointer(a, a_f, b)
}
_ => {
// Otherwise, just use subtyping rules.
self.subtype(a, b)
}
}
}

/// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
Expand Down
6 changes: 5 additions & 1 deletion src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1059,6 +1059,9 @@ fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
t_cast: Ty<'tcx>,
t_expr: Ty<'tcx>,
id: ast::NodeId) {
if t_cast.references_error() || t_expr.references_error() {
return;
}
let tstr = fcx.infcx().ty_to_string(t_cast);
fcx.type_error_message(span, |actual| {
format!("cast to unsized type: `{}` as `{}`", actual, tstr)
Expand Down Expand Up @@ -3507,9 +3510,10 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
let t_cast = structurally_resolved_type(fcx, expr.span, t_cast);
check_expr_with_expectation(fcx, e, ExpectCastableToType(t_cast));
let t_expr = fcx.expr_ty(e);
let t_cast = fcx.infcx().resolve_type_vars_if_possible(&t_cast);

// Eagerly check for some obvious errors.
if t_expr.references_error() {
if t_expr.references_error() || t_cast.references_error() {
fcx.write_error(id);
} else if !fcx.type_is_known_to_be_sized(t_cast, expr.span) {
report_cast_to_unsized_type(fcx, expr.span, t.span, e.span, t_cast, t_expr, id);
Expand Down
22 changes: 22 additions & 0 deletions src/test/compile-fail/coherence-projection-conflict-ty-param.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2016 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.

// Coherence error results because we do not know whether `T: Foo<P>` or not
// for the second impl.

use std::marker::PhantomData;

pub trait Foo<P> {}

impl <P, T: Foo<P>> Foo<P> for Option<T> {} //~ ERROR E0119

impl<T, U> Foo<T> for Option<U> { }

fn main() {}
2 changes: 1 addition & 1 deletion src/test/compile-fail/const-eval-overflow-4b.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use std::{u8, u16, u32, u64, usize};
const A_I8_T
: [u32; (i8::MAX as i8 + 1u8) as usize]
//~^ ERROR mismatched types
//~| the trait `core::ops::Add<u8>` is not implemented for the type `i8`
//~| ERROR the trait `core::ops::Add<u8>` is not implemented for the type `i8`
= [0; (i8::MAX as usize) + 1];

fn main() {
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-19692.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ struct Homura;

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

fn main() { }
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-21950.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ fn main() {
let x = &10 as
&Add;
//~^ ERROR the type parameter `RHS` must be explicitly specified in an object type because its default value `Self` references the type `Self`
//~^^ ERROR the value of the associated type `Output` (from the trait `core::ops::Add`) must be specified
//~| ERROR the value of the associated type `Output` (from the trait `core::ops::Add`) must be specified
}
4 changes: 3 additions & 1 deletion src/test/compile-fail/issue-23966.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@
// except according to those terms.

fn main() {
"".chars().fold(|_, _| (), ()); //~ ERROR is not implemented for the type `()`
"".chars().fold(|_, _| (), ());
//~^ ERROR E0277
//~| ERROR E0277
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-24352.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@

fn main() {
1.0f64 - 1.0;
1.0f64 - 1 //~ ERROR: is not implemented
1.0f64 - 1 //~ ERROR E0277
}
31 changes: 31 additions & 0 deletions src/test/compile-fail/issue-29857.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2016 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.


#![feature(rustc_attrs)]

use std::marker::PhantomData;

pub trait Foo<P> {}

impl <P, T: Foo<P>> Foo<P> for Option<T> {}

pub struct Qux<T> (PhantomData<*mut T>);

impl<T> Foo<*mut T> for Option<Qux<T>> {}

pub trait Bar {
type Output: 'static;
}

impl<T: 'static, W: Bar<Output = T>> Foo<*mut T> for W {}

#[rustc_error]
fn main() {} //~ ERROR compilation successful
4 changes: 3 additions & 1 deletion src/test/run-pass/issue-25810.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ fn main() {
println!("{:?}",y);
}

trait Foo {
trait Foo
where for<'a> &'a Self: Bar
{
fn foo<'a>(&'a self) -> <&'a Self as Bar>::Output;
}

Expand Down

0 comments on commit cedaee6

Please sign in to comment.