Skip to content

Rollup of 5 pull requests #41379

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

Closed
wants to merge 17 commits into from
Closed
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
6 changes: 3 additions & 3 deletions src/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/librustc/diagnostics.rs
Original file line number Diff line number Diff line change
@@ -1812,6 +1812,8 @@ makes a difference in practice.)

register_diagnostics! {
// E0006 // merged with E0005
// E0101, // replaced with E0282
// E0102, // replaced with E0282
// E0134,
// E0135,
E0278, // requirement is not satisfied
56 changes: 28 additions & 28 deletions src/librustc/infer/mod.rs
Original file line number Diff line number Diff line change
@@ -199,10 +199,8 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
// `tained_by_errors`) to avoid reporting certain kinds of errors.
err_count_on_creation: usize,

// This flag is used for debugging, and is set to true if there are
// any obligations set during the current snapshot. In that case, the
// snapshot can't be rolled back.
pub obligations_in_snapshot: Cell<bool>,
// This flag is true while there is an active snapshot.
in_snapshot: Cell<bool>,
}

/// A map returned by `skolemize_late_bound_regions()` indicating the skolemized
@@ -507,7 +505,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
projection_mode: Reveal::UserFacing,
tainted_by_errors_flag: Cell::new(false),
err_count_on_creation: self.sess.err_count(),
obligations_in_snapshot: Cell::new(false),
in_snapshot: Cell::new(false),
}
}
}
@@ -545,7 +543,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
projection_mode: projection_mode,
tainted_by_errors_flag: Cell::new(false),
err_count_on_creation: tcx.sess.err_count(),
obligations_in_snapshot: Cell::new(false),
in_snapshot: Cell::new(false),
}))
}
}
@@ -573,7 +571,7 @@ pub struct CombinedSnapshot {
int_snapshot: unify::Snapshot<ty::IntVid>,
float_snapshot: unify::Snapshot<ty::FloatVid>,
region_vars_snapshot: RegionSnapshot,
obligations_in_snapshot: bool,
was_in_snapshot: bool,
}

/// Helper trait for shortening the lifetimes inside a
@@ -734,6 +732,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.projection_mode
}

pub fn is_in_snapshot(&self) -> bool {
self.in_snapshot.get()
}

pub fn freshen<T:TypeFoldable<'tcx>>(&self, t: T) -> T {
t.fold_with(&mut self.freshener())
}
@@ -861,46 +863,45 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
result.map(move |t| InferOk { value: t, obligations: fields.obligations })
}

// Clear the "obligations in snapshot" flag, invoke the closure,
// Clear the "currently in a snapshot" flag, invoke the closure,
// then restore the flag to its original value. This flag is a
// debugging measure designed to detect cases where we start a
// snapshot, create type variables, register obligations involving
// those type variables in the fulfillment cx, and then have to
// unroll the snapshot, leaving "dangling type variables" behind.
// In such cases, the flag will be set by the fulfillment cx, and
// an assertion will fail when rolling the snapshot back. Very
// useful, much better than grovelling through megabytes of
// RUST_LOG output.
// snapshot, create type variables, and register obligations
// which may involve those type variables in the fulfillment cx,
// potentially leaving "dangling type variables" behind.
// In such cases, an assertion will fail when attempting to
// register obligations, within a snapshot. Very useful, much
// better than grovelling through megabytes of RUST_LOG output.
//
// HOWEVER, in some cases the flag is wrong. In particular, we
// HOWEVER, in some cases the flag is unhelpful. In particular, we
// sometimes create a "mini-fulfilment-cx" in which we enroll
// obligations. As long as this fulfillment cx is fully drained
// before we return, this is not a problem, as there won't be any
// escaping obligations in the main cx. In those cases, you can
// use this function.
pub fn save_and_restore_obligations_in_snapshot_flag<F, R>(&self, func: F) -> R
pub fn save_and_restore_in_snapshot_flag<F, R>(&self, func: F) -> R
where F: FnOnce(&Self) -> R
{
let flag = self.obligations_in_snapshot.get();
self.obligations_in_snapshot.set(false);
let flag = self.in_snapshot.get();
self.in_snapshot.set(false);
let result = func(self);
self.obligations_in_snapshot.set(flag);
self.in_snapshot.set(flag);
result
}

fn start_snapshot(&self) -> CombinedSnapshot {
debug!("start_snapshot()");

let obligations_in_snapshot = self.obligations_in_snapshot.get();
self.obligations_in_snapshot.set(false);
let in_snapshot = self.in_snapshot.get();
self.in_snapshot.set(true);

CombinedSnapshot {
projection_cache_snapshot: self.projection_cache.borrow_mut().snapshot(),
type_snapshot: self.type_variables.borrow_mut().snapshot(),
int_snapshot: self.int_unification_table.borrow_mut().snapshot(),
float_snapshot: self.float_unification_table.borrow_mut().snapshot(),
region_vars_snapshot: self.region_vars.start_snapshot(),
obligations_in_snapshot: obligations_in_snapshot,
was_in_snapshot: in_snapshot,
}
}

@@ -911,10 +912,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
int_snapshot,
float_snapshot,
region_vars_snapshot,
obligations_in_snapshot } = snapshot;
was_in_snapshot } = snapshot;

assert!(!self.obligations_in_snapshot.get());
self.obligations_in_snapshot.set(obligations_in_snapshot);
self.in_snapshot.set(was_in_snapshot);

self.projection_cache
.borrow_mut()
@@ -939,9 +939,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
int_snapshot,
float_snapshot,
region_vars_snapshot,
obligations_in_snapshot } = snapshot;
was_in_snapshot } = snapshot;

self.obligations_in_snapshot.set(obligations_in_snapshot);
self.in_snapshot.set(was_in_snapshot);

self.projection_cache
.borrow_mut()
125 changes: 84 additions & 41 deletions src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
@@ -25,16 +25,16 @@ use super::{

use errors::DiagnosticBuilder;
use fmt_macros::{Parser, Piece, Position};
use hir::{intravisit, Local, Pat};
use hir::{self, intravisit, Local, Pat, Body};
use hir::intravisit::{Visitor, NestedVisitorMap};
use hir::map::NodeExpr;
use hir::def_id::DefId;
use infer::{self, InferCtxt};
use infer::type_variable::TypeVariableOrigin;
use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL;
use std::fmt;
use syntax::ast;
use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
use syntax::ast::{self, NodeId};
use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable, TyInfer, TyVar};
use ty::error::ExpectedFound;
use ty::fast_reject;
use ty::fold::TypeFolder;
@@ -66,37 +66,52 @@ impl<'a, 'gcx, 'tcx> TraitErrorKey<'tcx> {
struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
target_ty: &'a Ty<'tcx>,
found_pattern: Option<&'a Pat>,
hir_map: &'a hir::map::Map<'gcx>,
found_local_pattern: Option<&'gcx Pat>,
found_arg_pattern: Option<&'gcx Pat>,
}

impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
fn is_match(&self, ty: Ty<'tcx>) -> bool {
ty == *self.target_ty || match (&ty.sty, &self.target_ty.sty) {
(&ty::TyInfer(ty::TyVar(a_vid)), &ty::TyInfer(ty::TyVar(b_vid))) =>
self.infcx.type_variables
.borrow_mut()
.sub_unified(a_vid, b_vid),

fn node_matches_type(&mut self, node_id: &'gcx NodeId) -> bool {
match self.infcx.tables.borrow().node_types.get(node_id) {
Some(&ty) => {
let ty = self.infcx.resolve_type_vars_if_possible(&ty);
ty.walk().any(|inner_ty| {
inner_ty == *self.target_ty || match (&inner_ty.sty, &self.target_ty.sty) {
(&TyInfer(TyVar(a_vid)), &TyInfer(TyVar(b_vid))) => {
self.infcx
.type_variables
.borrow_mut()
.sub_unified(a_vid, b_vid)
}
_ => false,
}
})
}
_ => false,
}
}
}

impl<'a, 'gcx, 'tcx> Visitor<'a> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'a> {
NestedVisitorMap::None
impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
NestedVisitorMap::OnlyBodies(&self.hir_map)
}

fn visit_local(&mut self, local: &'a Local) {
if let Some(&ty) = self.infcx.tables.borrow().node_types.get(&local.id) {
let ty = self.infcx.resolve_type_vars_if_possible(&ty);
let is_match = ty.walk().any(|t| self.is_match(t));
fn visit_local(&mut self, local: &'gcx Local) {
if self.found_local_pattern.is_none() && self.node_matches_type(&local.id) {
self.found_local_pattern = Some(&*local.pat);
}
intravisit::walk_local(self, local);
}

if is_match && self.found_pattern.is_none() {
self.found_pattern = Some(&*local.pat);
fn visit_body(&mut self, body: &'gcx Body) {
for argument in &body.arguments {
if self.found_arg_pattern.is_none() && self.node_matches_type(&argument.id) {
self.found_arg_pattern = Some(&*argument.pat);
}
}
intravisit::walk_local(self, local);
intravisit::walk_body(self, body);
}
}

@@ -721,6 +736,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
// coherence violation, so we don't report it here.

let predicate = self.resolve_type_vars_if_possible(&obligation.predicate);
let body_id = hir::BodyId { node_id: obligation.cause.body_id };
let span = obligation.cause.span;

debug!("maybe_report_ambiguity(predicate={:?}, obligation={:?})",
predicate,
@@ -768,10 +785,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.tcx.lang_items.sized_trait()
.map_or(false, |sized_id| sized_id == trait_ref.def_id())
{
self.need_type_info(obligation, self_ty);
self.need_type_info(body_id, span, self_ty);
} else {
let mut err = struct_span_err!(self.tcx.sess,
obligation.cause.span, E0283,
span, E0283,
"type annotations required: \
cannot resolve `{}`",
predicate);
@@ -785,7 +802,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
// Same hacky approach as above to avoid deluging user
// with error messages.
if !ty.references_error() && !self.tcx.sess.has_errors() {
self.need_type_info(obligation, ty);
self.need_type_info(body_id, span, ty);
}
}

@@ -796,7 +813,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder();
// both must be type variables, or the other would've been instantiated
assert!(a.is_ty_var() && b.is_ty_var());
self.need_type_info(obligation, a);
self.need_type_info(hir::BodyId { node_id: obligation.cause.body_id },
obligation.cause.span,
a);
}
}

@@ -874,42 +893,66 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
}

fn need_type_info(&self, obligation: &PredicateObligation<'tcx>, ty: Ty<'tcx>) {
pub fn need_type_info(&self, body_id: hir::BodyId, span: Span, ty: Ty<'tcx>) {
let ty = self.resolve_type_vars_if_possible(&ty);
let name = self.extract_type_name(&ty);
let ref cause = obligation.cause;

let mut err = struct_span_err!(self.tcx.sess,
cause.span,
E0282,
"type annotations needed");

err.span_label(cause.span, &format!("cannot infer type for `{}`", name));
let mut err_span = span;
let mut labels = vec![(span, format!("cannot infer type for `{}`", name))];

let mut local_visitor = FindLocalByTypeVisitor {
infcx: &self,
target_ty: &ty,
found_pattern: None,
hir_map: &self.tcx.hir,
found_local_pattern: None,
found_arg_pattern: None,
};

// #40294: cause.body_id can also be a fn declaration.
// Currently, if it's anything other than NodeExpr, we just ignore it
match self.tcx.hir.find(cause.body_id) {
match self.tcx.hir.find(body_id.node_id) {
Some(NodeExpr(expr)) => local_visitor.visit_expr(expr),
_ => ()
}

if let Some(pattern) = local_visitor.found_pattern {
let pattern_span = pattern.span;
if let Some(pattern) = local_visitor.found_arg_pattern {
err_span = pattern.span;
// We don't want to show the default label for closures.
//
// So, before clearing, the output would look something like this:
// ```
// let x = |_| { };
// - ^^^^ cannot infer type for `[_; 0]`
// |
// consider giving this closure parameter a type
// ```
//
// After clearing, it looks something like this:
// ```
// let x = |_| { };
// ^ consider giving this closure parameter a type
// ```
labels.clear();
labels.push((pattern.span, format!("consider giving this closure parameter a type")));
}

if let Some(pattern) = local_visitor.found_local_pattern {
if let Some(simple_name) = pattern.simple_name() {
err.span_label(pattern_span,
&format!("consider giving `{}` a type",
simple_name));
labels.push((pattern.span, format!("consider giving `{}` a type", simple_name)));
} else {
err.span_label(pattern_span, &format!("consider giving a type to pattern"));
labels.push((pattern.span, format!("consider giving the pattern a type")));
}
}

let mut err = struct_span_err!(self.tcx.sess,
err_span,
E0282,
"type annotations needed");

for (target_span, label_message) in labels {
err.span_label(target_span, &label_message);
}

err.emit();
}

2 changes: 1 addition & 1 deletion src/librustc/traits/fulfill.rs
Original file line number Diff line number Diff line change
@@ -171,7 +171,7 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {

debug!("register_predicate_obligation(obligation={:?})", obligation);

infcx.obligations_in_snapshot.set(true);
assert!(!infcx.is_in_snapshot());

if infcx.tcx.fulfilled_predicates.borrow().check_duplicate(&obligation.predicate) {
debug!("register_predicate_obligation: duplicate");
2 changes: 1 addition & 1 deletion src/librustc/traits/specialize/mod.rs
Original file line number Diff line number Diff line change
@@ -242,7 +242,7 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
// attempt to prove all of the predicates for impl2 given those for impl1
// (which are packed up in penv)

infcx.save_and_restore_obligations_in_snapshot_flag(|infcx| {
infcx.save_and_restore_in_snapshot_flag(|infcx| {
let mut fulfill_cx = FulfillmentContext::new();
for oblig in obligations.into_iter() {
fulfill_cx.register_predicate_obligation(&infcx, oblig);
6 changes: 3 additions & 3 deletions src/librustc_trans/cabi_x86_64.rs
Original file line number Diff line number Diff line change
@@ -229,12 +229,12 @@ pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType
};

if in_mem {
// `sret` / `byval` parameter thus one less integer register available
int_regs -= 1;

arg.make_indirect(ccx);
if is_arg {
arg.attrs.set(ArgAttribute::ByVal);
} else {
// `sret` parameter thus one less integer register available
int_regs -= 1;
}
} else {
// split into sized chunks passed individually
39 changes: 0 additions & 39 deletions src/librustc_typeck/check/assoc.rs

This file was deleted.

23 changes: 13 additions & 10 deletions src/librustc_typeck/check/autoderef.rs
Original file line number Diff line number Diff line change
@@ -149,22 +149,25 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
self.fcx.resolve_type_vars_if_possible(&self.cur_ty)
}

pub fn finalize<E>(self, pref: LvaluePreference, exprs: &[E])
where E: AsCoercionSite
{
pub fn finalize(self, pref: LvaluePreference, expr: &hir::Expr) {
let fcx = self.fcx;
fcx.register_infer_ok_obligations(self.finalize_as_infer_ok(pref, exprs));
fcx.register_infer_ok_obligations(self.finalize_as_infer_ok(pref, &[expr]));
}

pub fn finalize_as_infer_ok<E>(self, pref: LvaluePreference, exprs: &[E])
-> InferOk<'tcx, ()>
where E: AsCoercionSite
{
let methods: Vec<_> = self.steps
let Autoderef { fcx, span, mut obligations, steps, .. } = self;
let methods: Vec<_> = steps
.iter()
.map(|&(ty, kind)| {
if let AutoderefKind::Overloaded = kind {
self.fcx.try_overloaded_deref(self.span, None, ty, pref)
fcx.try_overloaded_deref(span, None, ty, pref)
.map(|InferOk { value, obligations: o }| {
obligations.extend(o);
value
})
} else {
None
}
@@ -174,22 +177,22 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
debug!("finalize({:?}) - {:?},{:?}",
pref,
methods,
self.obligations);
obligations);

for expr in exprs {
let expr = expr.as_coercion_site();
debug!("finalize - finalizing #{} - {:?}", expr.id, expr);
for (n, method) in methods.iter().enumerate() {
if let &Some(method) = method {
let method_call = MethodCall::autoderef(expr.id, n as u32);
self.fcx.tables.borrow_mut().method_map.insert(method_call, method);
fcx.tables.borrow_mut().method_map.insert(method_call, method);
}
}
}

InferOk {
value: (),
obligations: self.obligations
obligations
}
}
}
@@ -211,7 +214,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
base_expr: Option<&hir::Expr>,
base_ty: Ty<'tcx>,
lvalue_pref: LvaluePreference)
-> Option<MethodCallee<'tcx>> {
-> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
debug!("try_overloaded_deref({:?},{:?},{:?},{:?})",
span,
base_expr,
5 changes: 3 additions & 2 deletions src/librustc_typeck/check/callee.rs
Original file line number Diff line number Diff line change
@@ -55,7 +55,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
})
.next();
let callee_ty = autoderef.unambiguous_final_ty();
autoderef.finalize(LvaluePreference::NoPreference, &[callee_expr]);
autoderef.finalize(LvaluePreference::NoPreference, callee_expr);

let output = match result {
None => {
@@ -173,7 +173,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
adjusted_ty,
None) {
None => continue,
Some(method_callee) => {
Some(ok) => {
let method_callee = self.register_infer_ok_obligations(ok);
return Some(method_callee);
}
}
19 changes: 9 additions & 10 deletions src/librustc_typeck/check/coercion.rs
Original file line number Diff line number Diff line change
@@ -711,16 +711,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {

let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable);
let coerce = Coerce::new(self, cause);
self.commit_if_ok(|_| {
let ok = coerce.coerce(&[expr], source, target)?;
let adjustment = self.register_infer_ok_obligations(ok);
self.apply_adjustment(expr.id, adjustment);

// We should now have added sufficient adjustments etc to
// ensure that the type of expression, post-adjustment, is
// a subtype of target.
Ok(target)
})
let ok = self.commit_if_ok(|_| coerce.coerce(&[expr], source, target))?;

let adjustment = self.register_infer_ok_obligations(ok);
self.apply_adjustment(expr.id, adjustment);

// We should now have added sufficient adjustments etc to
// ensure that the type of expression, post-adjustment, is
// a subtype of target.
Ok(target)
}

/// Given some expressions, their known unified type and another expression,
64 changes: 25 additions & 39 deletions src/librustc_typeck/check/compare_method.rs
Original file line number Diff line number Diff line change
@@ -20,7 +20,6 @@ use rustc::util::common::ErrorReported;
use syntax::ast;
use syntax_pos::Span;

use super::assoc;
use super::{Inherited, FnCtxt};
use astconv::ExplicitSelf;

@@ -227,7 +226,6 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
tcx.infer_ctxt(trait_param_env, Reveal::UserFacing).enter(|infcx| {
let inh = Inherited::new(infcx);
let infcx = &inh.infcx;
let fulfillment_cx = &inh.fulfillment_cx;

debug!("compare_impl_method: caller_bounds={:?}",
infcx.parameter_environment.caller_bounds);
@@ -239,12 +237,11 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
infer::HigherRankedType,
&ty::Binder(impl_m_own_bounds.predicates));
for predicate in impl_m_own_bounds {
let traits::Normalized { value: predicate, .. } =
let traits::Normalized { value: predicate, obligations } =
traits::normalize(&mut selcx, normalize_cause.clone(), &predicate);

fulfillment_cx.borrow_mut().register_predicate_obligation(
&infcx,
traits::Obligation::new(cause.clone(), predicate));
inh.register_predicates(obligations);
inh.register_predicate(traits::Obligation::new(cause.clone(), predicate));
}

// We now need to check that the signature of the impl method is
@@ -277,11 +274,9 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let impl_sig =
impl_sig.subst(tcx, impl_to_skol_substs);
let impl_sig =
assoc::normalize_associated_types_in(&infcx,
&mut fulfillment_cx.borrow_mut(),
impl_m_span,
impl_m_body_id,
&impl_sig);
inh.normalize_associated_types_in(impl_m_span,
impl_m_body_id,
&impl_sig);
let impl_fty = tcx.mk_fn_ptr(ty::Binder(impl_sig));
debug!("compare_impl_method: impl_fty={:?}", impl_fty);

@@ -291,11 +286,9 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let trait_sig =
trait_sig.subst(tcx, trait_to_skol_substs);
let trait_sig =
assoc::normalize_associated_types_in(&infcx,
&mut fulfillment_cx.borrow_mut(),
impl_m_span,
impl_m_body_id,
&trait_sig);
inh.normalize_associated_types_in(impl_m_span,
impl_m_body_id,
&trait_sig);
let trait_fty = tcx.mk_fn_ptr(ty::Binder(trait_sig));

debug!("compare_impl_method: trait_fty={:?}", trait_fty);
@@ -344,7 +337,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,

// Check that all obligations are satisfied by the implementation's
// version.
if let Err(ref errors) = fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
infcx.report_fulfillment_errors(errors);
return Err(ErrorReported);
}
@@ -731,7 +724,8 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);

tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
let mut fulfillment_cx = traits::FulfillmentContext::new();
let inh = Inherited::new(infcx);
let infcx = &inh.infcx;

// The below is for the most part highly similar to the procedure
// for methods above. It is simpler in many respects, especially
@@ -761,31 +755,21 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let trait_ty = tcx.item_type(trait_c.def_id).subst(tcx, trait_to_skol_substs);
let mut cause = ObligationCause::misc(impl_c_span, impl_c_node_id);

let err = infcx.commit_if_ok(|_| {
// There is no "body" here, so just pass dummy id.
let impl_ty = assoc::normalize_associated_types_in(&infcx,
&mut fulfillment_cx,
impl_c_span,
ast::CRATE_NODE_ID,
&impl_ty);
// There is no "body" here, so just pass dummy id.
let impl_ty = inh.normalize_associated_types_in(impl_c_span,
impl_c_node_id,
&impl_ty);

debug!("compare_const_impl: impl_ty={:?}", impl_ty);
debug!("compare_const_impl: impl_ty={:?}", impl_ty);

let trait_ty = assoc::normalize_associated_types_in(&infcx,
&mut fulfillment_cx,
impl_c_span,
ast::CRATE_NODE_ID,
&trait_ty);
let trait_ty = inh.normalize_associated_types_in(impl_c_span,
impl_c_node_id,
&trait_ty);

debug!("compare_const_impl: trait_ty={:?}", trait_ty);
debug!("compare_const_impl: trait_ty={:?}", trait_ty);

infcx.sub_types(false, &cause, impl_ty, trait_ty)
.map(|InferOk { obligations, value: () }| {
for obligation in obligations {
fulfillment_cx.register_predicate_obligation(&infcx, obligation);
}
})
});
let err = infcx.sub_types(false, &cause, impl_ty, trait_ty)
.map(|ok| inh.register_infer_ok_obligations(ok));

if let Err(terr) = err {
debug!("checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
@@ -822,5 +806,7 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
&terr);
diag.emit();
}

// FIXME(#41323) Check the obligations in the fulfillment context.
});
}
7 changes: 4 additions & 3 deletions src/librustc_typeck/check/method/confirm.rs
Original file line number Diff line number Diff line change
@@ -137,7 +137,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
assert_eq!(n, pick.autoderefs);

autoderef.unambiguous_final_ty();
autoderef.finalize(LvaluePreference::NoPreference, &[self.self_expr]);
autoderef.finalize(LvaluePreference::NoPreference, self.self_expr);

let target = pick.unsize.unwrap_or(autoderefd_ty);
let target = target.adjust_for_autoref(self.tcx, autoref);
@@ -445,7 +445,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
"expr was deref-able {} times but now isn't?",
autoderefs);
});
autoderef.finalize(PreferMutLvalue, &[expr]);
autoderef.finalize(PreferMutLvalue, expr);
}
}
Some(_) | None => {}
@@ -543,7 +543,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
Some(&base_expr),
self.node_ty(base_expr.id),
PreferMutLvalue);
let method = method.expect("re-trying deref failed");
let ok = method.expect("re-trying deref failed");
let method = self.register_infer_ok_obligations(ok);
self.tables.borrow_mut().method_map.insert(method_call, method);
}
}
46 changes: 29 additions & 17 deletions src/librustc_typeck/check/method/mod.rs
Original file line number Diff line number Diff line change
@@ -17,7 +17,8 @@ use rustc::ty::subst::Substs;
use rustc::traits;
use rustc::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable};
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
use rustc::infer;
use rustc::ty::subst::Subst;
use rustc::infer::{self, InferOk};

use syntax::ast;
use syntax_pos::Span;
@@ -159,7 +160,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
trait_def_id: DefId,
self_ty: ty::Ty<'tcx>,
opt_input_types: Option<Vec<ty::Ty<'tcx>>>)
-> Option<ty::MethodCallee<'tcx>> {
-> Option<InferOk<'tcx, ty::MethodCallee<'tcx>>> {
self.lookup_method_in_trait_adjusted(span,
self_expr,
m_name,
@@ -190,7 +191,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
unsize: bool,
self_ty: ty::Ty<'tcx>,
opt_input_types: Option<Vec<ty::Ty<'tcx>>>)
-> Option<ty::MethodCallee<'tcx>> {
-> Option<InferOk<'tcx, ty::MethodCallee<'tcx>>> {
debug!("lookup_in_trait_adjusted(self_ty={:?}, self_expr={:?}, \
m_name={}, trait_def_id={:?})",
self_ty,
@@ -236,6 +237,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
assert_eq!(generics.regions.len(), 0);

debug!("lookup_in_trait_adjusted: method_item={:?}", method_item);
let mut obligations = vec![];

// Instantiate late-bound regions and substitute the trait
// parameters into the method type to get the actual method type.
@@ -248,10 +250,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let fn_sig = self.replace_late_bound_regions_with_fresh_var(span,
infer::FnCall,
&fn_sig).0;
let fn_sig = self.instantiate_type_scheme(span, trait_ref.substs, &fn_sig);
let fn_sig = fn_sig.subst(self.tcx, substs);
let fn_sig = match self.normalize_associated_types_in_as_infer_ok(span, &fn_sig) {
InferOk { value, obligations: o } => {
obligations.extend(o);
value
}
};
let transformed_self_ty = fn_sig.inputs()[0];
let method_ty = tcx.mk_fn_def(def_id, trait_ref.substs,
ty::Binder(fn_sig));
let method_ty = tcx.mk_fn_def(def_id, substs, ty::Binder(fn_sig));

debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}",
method_ty,
@@ -265,18 +272,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
//
// Note that as the method comes from a trait, it should not have
// any late-bound regions appearing in its bounds.
let method_bounds = self.instantiate_bounds(span, def_id, trait_ref.substs);
assert!(!method_bounds.has_escaping_regions());
self.add_obligations_for_parameters(traits::ObligationCause::misc(span, self.body_id),
&method_bounds);
let bounds = self.tcx.item_predicates(def_id).instantiate(self.tcx, substs);
let bounds = match self.normalize_associated_types_in_as_infer_ok(span, &bounds) {
InferOk { value, obligations: o } => {
obligations.extend(o);
value
}
};
assert!(!bounds.has_escaping_regions());

// Also register an obligation for the method type being well-formed.
self.register_wf_obligation(method_ty, span, traits::MiscObligation);
let cause = traits::ObligationCause::misc(span, self.body_id);
obligations.extend(traits::predicates_for_generics(cause.clone(), &bounds));

// FIXME(#18653) -- Try to resolve obligations, giving us more
// typing information, which can sometimes be needed to avoid
// pathological region inference failures.
self.select_obligations_where_possible();
// Also add an obligation for the method type being well-formed.
obligations.push(traits::Obligation::new(cause, ty::Predicate::WellFormed(method_ty)));

// Insert any adjustments needed (always an autoref of some mutability).
if let Some(self_expr) = self_expr {
@@ -317,7 +326,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {

debug!("callee = {:?}", callee);

Some(callee)
Some(InferOk {
obligations,
value: callee
})
}

pub fn resolve_ufcs(&self,
110 changes: 63 additions & 47 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
@@ -128,7 +128,6 @@ use rustc_back::slice;
use rustc::middle::const_val::eval_length;
use rustc_const_math::ConstInt;

mod assoc;
mod autoderef;
pub mod dropck;
pub mod _match;
@@ -536,7 +535,7 @@ impl<'a, 'gcx, 'tcx> InheritedBuilder<'a, 'gcx, 'tcx> {
}

impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
pub fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>) -> Self {
fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>) -> Self {
Inherited {
infcx: infcx,
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
@@ -547,20 +546,55 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
}
}

fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) {
debug!("register_predicate({:?})", obligation);
if obligation.has_escaping_regions() {
span_bug!(obligation.cause.span, "escaping regions in predicate {:?}",
obligation);
}
self.fulfillment_cx
.borrow_mut()
.register_predicate_obligation(self, obligation);
}

fn register_predicates(&self, obligations: Vec<traits::PredicateObligation<'tcx>>) {
for obligation in obligations {
self.register_predicate(obligation);
}
}

fn register_infer_ok_obligations<T>(&self, infer_ok: InferOk<'tcx, T>) -> T {
self.register_predicates(infer_ok.obligations);
infer_ok.value
}

fn normalize_associated_types_in<T>(&self,
span: Span,
body_id: ast::NodeId,
value: &T)
-> T
value: &T) -> T
where T : TypeFoldable<'tcx>
{
assoc::normalize_associated_types_in(self,
&mut self.fulfillment_cx.borrow_mut(),
span,
body_id,
value)
let ok = self.normalize_associated_types_in_as_infer_ok(span, body_id, value);
self.register_infer_ok_obligations(ok)
}

fn normalize_associated_types_in_as_infer_ok<T>(&self,
span: Span,
body_id: ast::NodeId,
value: &T)
-> InferOk<'tcx, T>
where T : TypeFoldable<'tcx>
{
debug!("normalize_associated_types_in(value={:?})", value);
let mut selcx = traits::SelectionContext::new(self);
let cause = ObligationCause::misc(span, body_id);
let traits::Normalized { value, obligations } =
traits::normalize(&mut selcx, cause, value);
debug!("normalize_associated_types_in: result={:?} predicates={:?}",
value,
obligations);
InferOk { value, obligations }
}
}

struct CheckItemTypesVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> }
@@ -1713,14 +1747,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-> ty::InstantiatedPredicates<'tcx> {
let bounds = self.tcx.item_predicates(def_id);
let result = bounds.instantiate(self.tcx, substs);
let result = self.normalize_associated_types_in(span, &result.predicates);
let result = self.normalize_associated_types_in(span, &result);
debug!("instantiate_bounds(bounds={:?}, substs={:?}) = {:?}",
bounds,
substs,
result);
ty::InstantiatedPredicates {
predicates: result
}
result
}

/// Replace all anonymized types with fresh inference variables
@@ -1763,7 +1795,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
where T : TypeFoldable<'tcx>
{
self.inh.normalize_associated_types_in(span, self.body_id, value)
let ok = self.normalize_associated_types_in_as_infer_ok(span, value);
self.register_infer_ok_obligations(ok)
}

fn normalize_associated_types_in_as_infer_ok<T>(&self, span: Span, value: &T)
-> InferOk<'tcx, T>
where T : TypeFoldable<'tcx>
{
self.inh.normalize_associated_types_in_as_infer_ok(span, self.body_id, value)
}

pub fn write_nil(&self, node_id: ast::NodeId) {
@@ -1804,32 +1844,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
.register_bound(self, ty, def_id, cause);
}

pub fn register_predicate(&self,
obligation: traits::PredicateObligation<'tcx>)
{
debug!("register_predicate({:?})", obligation);
if obligation.has_escaping_regions() {
span_bug!(obligation.cause.span, "escaping regions in predicate {:?}",
obligation);
}
self.fulfillment_cx
.borrow_mut()
.register_predicate_obligation(self, obligation);
}

pub fn register_predicates(&self,
obligations: Vec<traits::PredicateObligation<'tcx>>)
{
for obligation in obligations {
self.register_predicate(obligation);
}
}

pub fn register_infer_ok_obligations<T>(&self, infer_ok: InferOk<'tcx, T>) -> T {
self.register_predicates(infer_ok.obligations);
infer_ok.value
}

pub fn to_ty(&self, ast_t: &hir::Ty) -> Ty<'tcx> {
let t = AstConv::ast_ty_to_ty(self, ast_t);
self.register_wf_obligation(t, ast_t.span, traits::MiscObligation);
@@ -2072,12 +2086,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
expr, base_expr, adj_ty, autoderefs,
false, lvalue_pref, idx_ty)
{
autoderef.finalize(lvalue_pref, &[base_expr]);
autoderef.finalize(lvalue_pref, base_expr);
return Some(final_mt);
}

if let ty::TyArray(element_ty, _) = adj_ty.sty {
autoderef.finalize(lvalue_pref, &[base_expr]);
autoderef.finalize(lvalue_pref, base_expr);
let adjusted_ty = self.tcx.mk_slice(element_ty);
return self.try_index_step(
MethodCall::expr(expr.id), expr, base_expr,
@@ -2161,8 +2175,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// If some lookup succeeds, write callee into table and extract index/element
// type from the method signature.
// If some lookup succeeded, install method in table
method.map(|method| {
method.map(|ok| {
debug!("try_index_step: success, using overloaded indexing");
let method = self.register_infer_ok_obligations(ok);
self.tables.borrow_mut().method_map.insert(method_call, method);
(input_ty, self.make_overloaded_lvalue_return_type(method).ty)
})
@@ -2586,7 +2601,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// we can. We don't care if some things turn
// out unconstrained or ambiguous, as we're
// just trying to get hints here.
let result = self.save_and_restore_obligations_in_snapshot_flag(|_| {
let result = self.save_and_restore_in_snapshot_flag(|_| {
let mut fulfill = FulfillmentContext::new();
let ok = ok; // FIXME(#30046)
for obligation in ok.obligations {
@@ -2755,7 +2770,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
if let Some(field) = base_def.struct_variant().find_field_named(field.node) {
let field_ty = self.field_ty(expr.span, field, substs);
if self.tcx.vis_is_accessible_from(field.vis, self.body_id) {
autoderef.finalize(lvalue_pref, &[base]);
autoderef.finalize(lvalue_pref, base);
self.apply_autoderef_adjustment(base.id, autoderefs, base_t);

self.tcx.check_stability(field.did, expr.id, expr.span);
@@ -2879,7 +2894,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
};

if let Some(field_ty) = field {
autoderef.finalize(lvalue_pref, &[base]);
autoderef.finalize(lvalue_pref, base);
self.apply_autoderef_adjustment(base.id, autoderefs, base_t);
return field_ty;
}
@@ -3292,8 +3307,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {

if let Some(mt) = oprnd_t.builtin_deref(true, NoPreference) {
oprnd_t = mt.ty;
} else if let Some(method) = self.try_overloaded_deref(
} else if let Some(ok) = self.try_overloaded_deref(
expr.span, Some(&oprnd), oprnd_t, lvalue_pref) {
let method = self.register_infer_ok_obligations(ok);
oprnd_t = self.make_overloaded_lvalue_return_type(method).ty;
self.tables.borrow_mut().method_map.insert(MethodCall::expr(expr.id),
method);
19 changes: 10 additions & 9 deletions src/librustc_typeck/check/op.rs
Original file line number Diff line number Diff line change
@@ -398,20 +398,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {

let method = match trait_did {
Some(trait_did) => {
self.lookup_method_in_trait_adjusted(expr.span,
Some(lhs_expr),
opname,
trait_did,
0,
false,
lhs_ty,
Some(other_tys))
self.lookup_method_in_trait(expr.span,
Some(lhs_expr),
opname,
trait_did,
lhs_ty,
Some(other_tys))
}
None => None
};

match method {
Some(method) => {
Some(ok) => {
let method = self.register_infer_ok_obligations(ok);
self.select_obligations_where_possible();

let method_ty = method.ty;

// HACK(eddyb) Fully qualified path to work around a resolve bug.
251 changes: 85 additions & 166 deletions src/librustc_typeck/check/writeback.rs

Large diffs are not rendered by default.

50 changes: 3 additions & 47 deletions src/librustc_typeck/diagnostics.rs
Original file line number Diff line number Diff line change
@@ -1351,50 +1351,6 @@ extern "rust-intrinsic" {
```
"##,

E0101: r##"
You hit this error because the compiler lacks the information to
determine a type for this expression. Erroneous code example:
```compile_fail,E0101
let x = |_| {}; // error: cannot determine a type for this expression
```
You have two possibilities to solve this situation:
* Give an explicit definition of the expression
* Infer the expression
Examples:
```
let x = |_ : u32| {}; // ok!
// or:
let x = |_| {};
x(0u32);
```
"##,

E0102: r##"
You hit this error because the compiler lacks the information to
determine the type of this variable. Erroneous code example:
```compile_fail,E0282
// could be an array of anything
let x = []; // error: cannot determine a type for this local variable
```
To solve this situation, constrain the type of the variable.
Examples:
```
#![allow(unused_variables)]
fn main() {
let x: [u8; 0] = [];
}
```
"##,

E0107: r##"
This error means that an incorrect number of lifetime parameters were provided
for a type (like a struct or enum) or trait:
@@ -4146,8 +4102,8 @@ register_diagnostics! {
// E0068,
// E0085,
// E0086,
E0103, // @GuillaumeGomez: I was unable to get this error, try your best!
E0104,
// E0103,
// E0104,
// E0123,
// E0127,
// E0129,
@@ -4164,7 +4120,7 @@ register_diagnostics! {
// E0188, // can not cast an immutable reference to a mutable pointer
// E0189, // deprecated: can only cast a boxed pointer to a boxed object
// E0190, // deprecated: can only cast a &-pointer to an &-object
E0196, // cannot determine a type for this closure
// E0196, // cannot determine a type for this closure
E0203, // type parameter has more than one relaxed default bound,
// and only one is supported
E0208,
2 changes: 1 addition & 1 deletion src/stage0.txt
Original file line number Diff line number Diff line change
@@ -12,4 +12,4 @@
# tarball for a stable release you'll likely see `1.x.0-$date` where `1.x.0` was
# released on `$date`

rustc: beta-2017-03-21
rustc: beta-2017-04-05
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-12187-1.rs
Original file line number Diff line number Diff line change
@@ -16,5 +16,5 @@ fn main() {
let &v = new();
//~^ ERROR type annotations needed [E0282]
//~| NOTE cannot infer type for `_`
//~| NOTE consider giving a type to pattern
//~| NOTE consider giving the pattern a type
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-12187-2.rs
Original file line number Diff line number Diff line change
@@ -16,5 +16,5 @@ fn main() {
let &v = new();
//~^ ERROR type annotations needed [E0282]
//~| NOTE cannot infer type for `_`
//~| NOTE consider giving a type to pattern
//~| NOTE consider giving the pattern a type
}
15 changes: 15 additions & 0 deletions src/test/run-make/extern-fn-struct-passing-abi/test.c
Original file line number Diff line number Diff line change
@@ -137,6 +137,21 @@ void byval_rect_with_float(int32_t a, int32_t b, float c, int32_t d,
assert(s.d == 556);
}

// System V x86_64 ABI:
// a, b, d, e, f should be byval pointer (on the stack)
// g passed via register (fixes #41375)
//
// Win64 ABI:
// a, b, d, e, f, g should be byval pointer
void byval_rect_with_many_huge(struct Huge a, struct Huge b, struct Huge c,
struct Huge d, struct Huge e, struct Huge f,
struct Rect g) {
assert(g.a == 123);
assert(g.b == 456);
assert(g.c == 789);
assert(g.d == 420);
}

// System V x86_64 & Win64 ABI:
// a, b should be in registers
// s should be split across 2 integer registers
8 changes: 8 additions & 0 deletions src/test/run-make/extern-fn-struct-passing-abi/test.rs
Original file line number Diff line number Diff line change
@@ -64,6 +64,8 @@ extern {

fn byval_rect_with_float(a: i32, b: i32, c: f32, d: i32, e: i32, f: i32, s: Rect);

fn byval_rect_with_many_huge(a: Huge, b: Huge, c: Huge, d: Huge, e: Huge, f: Huge, g: Rect);

fn split_rect(a: i32, b: i32, s: Rect);

fn split_rect_floats(a: f32, b: f32, s: FloatRect);
@@ -95,6 +97,12 @@ fn main() {
byval_many_rect(1, 2, 3, 4, 5, 6, s);
byval_rect_floats(1., 2., 3., 4., 5., 6., 7., s, u);
byval_rect_with_float(1, 2, 3.0, 4, 5, 6, s);
byval_rect_with_many_huge(v, v, v, v, v v, Rect {
a: 123,
b: 456,
c: 789,
d: 420
});
split_rect(1, 2, s);
split_rect_floats(1., 2., u);
split_rect_with_floats(1, 2, 3.0, 4, 5.0, 6, s);
4 changes: 4 additions & 0 deletions src/test/run-pass/coerce-overloaded-autoderef.rs
Original file line number Diff line number Diff line change
@@ -68,4 +68,8 @@ fn use_vec_ref(v: &Vec<u8>) {
use_slice(&&&mut &&&v);
}

fn use_op_rhs(s: &mut String) {
*s += {&String::from(" ")};
}

pub fn main() {}
Original file line number Diff line number Diff line change
@@ -9,5 +9,5 @@
// except according to those terms.

fn main() {
let (x,) = (vec![],);
let x = [];
}
10 changes: 10 additions & 0 deletions src/test/ui/type-check/cannot_infer_local_or_array.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error[E0282]: type annotations needed
--> $DIR/cannot_infer_local_or_array.rs:12:13
|
12 | let x = [];
| - ^^ cannot infer type for `_`
| |
| consider giving `x` a type

error: aborting due to previous error

File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0282]: type annotations needed
--> $DIR/issue-38812.rs:12:13
--> $DIR/cannot_infer_local_or_vec.rs:12:13
|
12 | let x = vec![];
| - ^^^^^^ cannot infer type for `T`
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@@ -9,7 +9,5 @@
// except according to those terms.

fn main() {
let x = |_| {};
//~^ ERROR E0101
//~| NOTE cannot resolve type of expression
let (x, ) = (vec![], );
}
12 changes: 12 additions & 0 deletions src/test/ui/type-check/cannot_infer_local_or_vec_in_tuples.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0282]: type annotations needed
--> $DIR/cannot_infer_local_or_vec_in_tuples.rs:12:18
|
12 | let (x, ) = (vec![], );
| ----- ^^^^^^ cannot infer type for `T`
| |
| consider giving the pattern a type
|
= note: this error originates in a macro outside of the current crate

error: aborting due to previous error

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@@ -10,10 +10,6 @@

fn main() { }

// Before these errors would ICE as "cat_expr Errd" because the errors
// were unknown when the bug was triggered.

fn unconstrained_type() {
[];
//~^ ERROR cannot determine a type for this expression: unconstrained type
}
8 changes: 8 additions & 0 deletions src/test/ui/type-check/issue-22897.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
error[E0282]: type annotations needed
--> $DIR/issue-22897.rs:14:5
|
14 | [];
| ^^ cannot infer type for `[_; 0]`

error: aborting due to previous error

12 changes: 0 additions & 12 deletions src/test/ui/type-check/issue-38812-2.stderr

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@@ -9,8 +9,5 @@
// except according to those terms.

fn main() {
let x = [];
//~^ ERROR type annotations needed
//~| NOTE consider giving `x` a type
//~| NOTE cannot infer type for `_`
let x = |_| { };
}
8 changes: 8 additions & 0 deletions src/test/ui/type-check/unknown_type_for_closure.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
error[E0282]: type annotations needed
--> $DIR/unknown_type_for_closure.rs:12:14
|
12 | let x = |_| { };
| ^ consider giving this closure parameter a type

error: aborting due to previous error

2 changes: 1 addition & 1 deletion src/tools/rustbook/Cargo.toml
Original file line number Diff line number Diff line change
@@ -8,5 +8,5 @@ license = "MIT/Apache-2.0"
clap = "2.19.3"

[dependencies.mdbook]
version = "0.0.18"
version = "0.0.19"
default-features = false