suppress trait errors that are implied by other errors
Instead of suppressing only trait errors that are "exact duplicates", display only the "most high-level" error when there are multiple trait errors with the same span that imply each-other. e.g. when there are both `[closure]: Fn` and `[closure]: FnOnce`, omit displaying the `[closure]: FnOnce` bound.
This commit is contained in:
parent
dfa7e21e4e
commit
7b9519a5d4
@ -74,6 +74,7 @@ use syntax_pos::{Pos, Span};
|
||||
use errors::{DiagnosticBuilder, DiagnosticStyledString};
|
||||
|
||||
mod note;
|
||||
mod need_type_info;
|
||||
|
||||
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
pub fn note_and_explain_region(self,
|
||||
|
153
src/librustc/infer/error_reporting/need_type_info.rs
Normal file
153
src/librustc/infer/error_reporting/need_type_info.rs
Normal file
@ -0,0 +1,153 @@
|
||||
// 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.
|
||||
//
|
||||
// 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.
|
||||
|
||||
use hir::{self, map, Local, Pat, Body};
|
||||
use hir::intravisit::{self, Visitor, NestedVisitorMap};
|
||||
use infer::InferCtxt;
|
||||
use infer::type_variable::TypeVariableOrigin;
|
||||
use ty::{self, Ty, TyInfer, TyVar};
|
||||
|
||||
use syntax::ast::NodeId;
|
||||
use syntax_pos::Span;
|
||||
|
||||
struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
||||
target_ty: &'a Ty<'tcx>,
|
||||
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 node_matches_type(&mut self, node_id: NodeId) -> bool {
|
||||
let ty_opt = self.infcx.in_progress_tables.and_then(|tables| {
|
||||
tables.borrow().node_id_to_type_opt(node_id)
|
||||
});
|
||||
match ty_opt {
|
||||
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,
|
||||
}
|
||||
})
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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: &'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);
|
||||
}
|
||||
|
||||
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_body(self, body);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String {
|
||||
if let ty::TyInfer(ty::TyVar(ty_vid)) = (*ty).sty {
|
||||
let ty_vars = self.type_variables.borrow();
|
||||
if let TypeVariableOrigin::TypeParameterDefinition(_, name) =
|
||||
*ty_vars.var_origin(ty_vid) {
|
||||
name.to_string()
|
||||
} else {
|
||||
ty.to_string()
|
||||
}
|
||||
} else {
|
||||
ty.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
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 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,
|
||||
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(body_id.node_id) {
|
||||
Some(map::NodeExpr(expr)) => local_visitor.visit_expr(expr),
|
||||
_ => ()
|
||||
}
|
||||
|
||||
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() {
|
||||
labels.push((pattern.span, format!("consider giving `{}` a type", simple_name)));
|
||||
} else {
|
||||
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();
|
||||
}
|
||||
}
|
@ -36,7 +36,7 @@ use std::fmt;
|
||||
use syntax::ast;
|
||||
use errors::DiagnosticBuilder;
|
||||
use syntax_pos::{self, Span, DUMMY_SP};
|
||||
use util::nodemap::{FxHashMap, FxHashSet};
|
||||
use util::nodemap::FxHashMap;
|
||||
use arena::DroplessArena;
|
||||
|
||||
use self::combine::CombineFields;
|
||||
@ -110,7 +110,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
|
||||
// the set of predicates on which errors have been reported, to
|
||||
// avoid reporting the same error twice.
|
||||
pub reported_trait_errors: RefCell<FxHashSet<traits::TraitErrorKey<'tcx>>>,
|
||||
pub reported_trait_errors: RefCell<FxHashMap<Span, Vec<ty::Predicate<'tcx>>>>,
|
||||
|
||||
// When an error occurs, we want to avoid reporting "derived"
|
||||
// errors that are due to this original failure. Normally, we
|
||||
@ -350,6 +350,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
|
||||
global_tcx: self,
|
||||
arena: DroplessArena::new(),
|
||||
fresh_tables: None,
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -381,7 +382,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
|
||||
region_vars: RegionVarBindings::new(tcx),
|
||||
selection_cache: traits::SelectionCache::new(),
|
||||
evaluation_cache: traits::EvaluationCache::new(),
|
||||
reported_trait_errors: RefCell::new(FxHashSet()),
|
||||
reported_trait_errors: RefCell::new(FxHashMap()),
|
||||
tainted_by_errors_flag: Cell::new(false),
|
||||
err_count_on_creation: tcx.sess.err_count(),
|
||||
in_snapshot: Cell::new(false),
|
||||
|
@ -18,6 +18,7 @@ use super::{
|
||||
OutputTypeParameterMismatch,
|
||||
TraitNotObjectSafe,
|
||||
PredicateObligation,
|
||||
Reveal,
|
||||
SelectionContext,
|
||||
SelectionError,
|
||||
ObjectSafetyViolation,
|
||||
@ -25,16 +26,14 @@ use super::{
|
||||
|
||||
use errors::DiagnosticBuilder;
|
||||
use fmt_macros::{Parser, Piece, Position};
|
||||
use hir::{self, intravisit, Local, Pat, Body};
|
||||
use hir::intravisit::{Visitor, NestedVisitorMap};
|
||||
use hir::map::NodeExpr;
|
||||
use hir;
|
||||
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::{self, NodeId};
|
||||
use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable, TyInfer, TyVar};
|
||||
use syntax::ast;
|
||||
use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
|
||||
use ty::error::{ExpectedFound, TypeError};
|
||||
use ty::fast_reject;
|
||||
use ty::fold::TypeFolder;
|
||||
@ -44,96 +43,113 @@ use util::nodemap::{FxHashMap, FxHashSet};
|
||||
|
||||
use syntax_pos::{DUMMY_SP, Span};
|
||||
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
pub struct TraitErrorKey<'tcx> {
|
||||
span: Span,
|
||||
predicate: ty::Predicate<'tcx>
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> TraitErrorKey<'tcx> {
|
||||
fn from_error(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
e: &FulfillmentError<'tcx>) -> Self {
|
||||
let predicate =
|
||||
infcx.resolve_type_vars_if_possible(&e.obligation.predicate);
|
||||
TraitErrorKey {
|
||||
span: e.obligation.cause.span,
|
||||
predicate: infcx.tcx.erase_regions(&predicate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
||||
target_ty: &'a Ty<'tcx>,
|
||||
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 node_matches_type(&mut self, node_id: NodeId) -> bool {
|
||||
let ty_opt = self.infcx.in_progress_tables.and_then(|tables| {
|
||||
tables.borrow().node_id_to_type_opt(node_id)
|
||||
});
|
||||
match ty_opt {
|
||||
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,
|
||||
}
|
||||
})
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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: &'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);
|
||||
}
|
||||
|
||||
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_body(self, body);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
pub fn report_fulfillment_errors(&self, errors: &Vec<FulfillmentError<'tcx>>) {
|
||||
for error in errors {
|
||||
self.report_fulfillment_error(error);
|
||||
pub fn report_fulfillment_errors(&self,
|
||||
errors: &Vec<FulfillmentError<'tcx>>) {
|
||||
#[derive(Debug)]
|
||||
struct ErrorDescriptor<'tcx> {
|
||||
predicate: ty::Predicate<'tcx>,
|
||||
index: Option<usize>, // None if this is an old error
|
||||
}
|
||||
|
||||
let mut error_map : FxHashMap<_, _> =
|
||||
self.reported_trait_errors.borrow().iter().map(|(&span, predicates)| {
|
||||
(span, predicates.iter().map(|predicate| ErrorDescriptor {
|
||||
predicate: predicate.clone(),
|
||||
index: None
|
||||
}).collect())
|
||||
}).collect();
|
||||
|
||||
for (index, error) in errors.iter().enumerate() {
|
||||
error_map.entry(error.obligation.cause.span).or_insert(Vec::new()).push(
|
||||
ErrorDescriptor {
|
||||
predicate: error.obligation.predicate.clone(),
|
||||
index: Some(index)
|
||||
});
|
||||
|
||||
self.reported_trait_errors.borrow_mut()
|
||||
.entry(error.obligation.cause.span).or_insert(Vec::new())
|
||||
.push(error.obligation.predicate.clone());
|
||||
}
|
||||
|
||||
// We do this in 2 passes because we want to display errors in order, tho
|
||||
// maybe it *is* better to sort errors by span or something.
|
||||
let mut is_suppressed: Vec<bool> = errors.iter().map(|_| false).collect();
|
||||
for (_, error_set) in error_map.iter() {
|
||||
// We want to suppress "duplicate" errors with the same span.
|
||||
for error in error_set {
|
||||
if let Some(index) = error.index {
|
||||
// Suppress errors that are either:
|
||||
// 1) strictly implied by another error.
|
||||
// 2) implied by an error with a smaller index.
|
||||
for error2 in error_set {
|
||||
if error2.index.map_or(false, |index2| is_suppressed[index2]) {
|
||||
// Avoid errors being suppressed by already-suppressed
|
||||
// errors, to prevent all errors from being suppressed
|
||||
// at once.
|
||||
continue
|
||||
}
|
||||
|
||||
if self.error_implies(&error2.predicate, &error.predicate) &&
|
||||
!(error2.index >= error.index &&
|
||||
self.error_implies(&error.predicate, &error2.predicate))
|
||||
{
|
||||
info!("skipping {:?} (implied by {:?})", error, error2);
|
||||
is_suppressed[index] = true;
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (error, suppressed) in errors.iter().zip(is_suppressed) {
|
||||
if !suppressed {
|
||||
self.report_fulfillment_error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn report_fulfillment_error(&self,
|
||||
error: &FulfillmentError<'tcx>) {
|
||||
let error_key = TraitErrorKey::from_error(self, error);
|
||||
debug!("report_fulfillment_errors({:?}) - key={:?}",
|
||||
error, error_key);
|
||||
if !self.reported_trait_errors.borrow_mut().insert(error_key) {
|
||||
debug!("report_fulfillment_errors: skipping duplicate");
|
||||
return;
|
||||
// returns if `cond` not occuring implies that `error` does not occur - i.e. that
|
||||
// `error` occuring implies that `cond` occurs.
|
||||
fn error_implies(&self,
|
||||
cond: &ty::Predicate<'tcx>,
|
||||
error: &ty::Predicate<'tcx>)
|
||||
-> bool
|
||||
{
|
||||
if cond == error {
|
||||
return true
|
||||
}
|
||||
|
||||
let (cond, error) = match (cond, error) {
|
||||
(&ty::Predicate::Trait(..), &ty::Predicate::Trait(ref error))
|
||||
=> (cond, error),
|
||||
_ => {
|
||||
// FIXME: make this work in other cases too.
|
||||
return false
|
||||
}
|
||||
};
|
||||
|
||||
for implication in super::elaborate_predicates(self.tcx, vec![cond.clone()]) {
|
||||
if let ty::Predicate::Trait(implication) = implication {
|
||||
let error = error.to_poly_trait_ref();
|
||||
let implication = implication.to_poly_trait_ref();
|
||||
// FIXME: I'm just not taking associated types at all here.
|
||||
// Eventually I'll need to implement param-env-aware
|
||||
// `Γ₁ ⊦ φ₁ => Γ₂ ⊦ φ₂` logic.
|
||||
let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
|
||||
if let Ok(_) = self.can_sub(param_env, error, implication) {
|
||||
debug!("error_implies: {:?} -> {:?} -> {:?}", cond, error, implication);
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) {
|
||||
debug!("report_fulfillment_errors({:?})", error);
|
||||
match error.code {
|
||||
FulfillmentErrorCode::CodeSelectionError(ref e) => {
|
||||
self.report_selection_error(&error.obligation, e);
|
||||
@ -1008,83 +1024,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
})
|
||||
}
|
||||
|
||||
fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String {
|
||||
if let ty::TyInfer(ty::TyVar(ty_vid)) = (*ty).sty {
|
||||
let ty_vars = self.type_variables.borrow();
|
||||
if let TypeVariableOrigin::TypeParameterDefinition(_, name) =
|
||||
*ty_vars.var_origin(ty_vid) {
|
||||
name.to_string()
|
||||
} else {
|
||||
ty.to_string()
|
||||
}
|
||||
} else {
|
||||
ty.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
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 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,
|
||||
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(body_id.node_id) {
|
||||
Some(NodeExpr(expr)) => local_visitor.visit_expr(expr),
|
||||
_ => ()
|
||||
}
|
||||
|
||||
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() {
|
||||
labels.push((pattern.span, format!("consider giving `{}` a type", simple_name)));
|
||||
} else {
|
||||
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();
|
||||
}
|
||||
|
||||
fn note_obligation_cause<T>(&self,
|
||||
err: &mut DiagnosticBuilder,
|
||||
obligation: &Obligation<'tcx, T>)
|
||||
@ -1205,4 +1144,3 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
suggested_limit));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,6 @@ use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
|
||||
pub use self::error_reporting::TraitErrorKey;
|
||||
pub use self::coherence::orphan_check;
|
||||
pub use self::coherence::overlapping_impls;
|
||||
pub use self::coherence::OrphanCheckErr;
|
||||
|
@ -1101,7 +1101,10 @@ pub fn monitor<F: FnOnce() + Send + 'static>(f: F) {
|
||||
}
|
||||
|
||||
let xs = ["the compiler unexpectedly panicked. this is a bug.".to_string(),
|
||||
format!("we would appreciate a bug report: {}", BUG_REPORT_URL)];
|
||||
format!("we would appreciate a bug report: {}", BUG_REPORT_URL),
|
||||
format!("rustc {} running on {}",
|
||||
option_env!("CFG_VERSION").unwrap_or("unknown_version"),
|
||||
config::host_triple())];
|
||||
for note in &xs {
|
||||
handler.emit(&MultiSpan::new(),
|
||||
¬e,
|
||||
|
@ -18,5 +18,4 @@ fn main() {
|
||||
let _x: extern "C" fn() = f; // OK
|
||||
is_fn(f);
|
||||
//~^ ERROR `extern "C" fn() {f}: std::ops::Fn<()>` is not satisfied
|
||||
//~| ERROR `extern "C" fn() {f}: std::ops::FnOnce<()>` is not satisfied
|
||||
}
|
||||
|
@ -28,5 +28,4 @@ fn main() {
|
||||
|
||||
needs_fn(1);
|
||||
//~^ ERROR : std::ops::Fn<(isize,)>`
|
||||
//~| ERROR : std::ops::FnOnce<(isize,)>`
|
||||
}
|
||||
|
@ -17,6 +17,5 @@ fn main() {
|
||||
let _: &mut Fn() = unsafe {
|
||||
&mut *(ptr as *mut Fn())
|
||||
//~^ ERROR `(): std::ops::Fn<()>` is not satisfied
|
||||
//~| ERROR `(): std::ops::FnOnce<()>` is not satisfied
|
||||
};
|
||||
}
|
||||
|
@ -11,5 +11,4 @@
|
||||
fn main() {
|
||||
"".chars().fold(|_, _| (), ());
|
||||
//~^ ERROR E0277
|
||||
//~| ERROR E0277
|
||||
}
|
||||
|
@ -17,8 +17,8 @@ use std::ops::*;
|
||||
struct AllTheRanges {
|
||||
a: Range<usize>,
|
||||
//~^ ERROR PartialOrd
|
||||
//~^^ ERROR PartialOrd
|
||||
//~^^^ ERROR Ord
|
||||
//~^^ ERROR Ord
|
||||
//~^^^ ERROR binary operation
|
||||
//~^^^^ ERROR binary operation
|
||||
//~^^^^^ ERROR binary operation
|
||||
//~^^^^^^ ERROR binary operation
|
||||
@ -26,11 +26,10 @@ struct AllTheRanges {
|
||||
//~^^^^^^^^ ERROR binary operation
|
||||
//~^^^^^^^^^ ERROR binary operation
|
||||
//~^^^^^^^^^^ ERROR binary operation
|
||||
//~^^^^^^^^^^^ ERROR binary operation
|
||||
b: RangeTo<usize>,
|
||||
//~^ ERROR PartialOrd
|
||||
//~^^ ERROR PartialOrd
|
||||
//~^^^ ERROR Ord
|
||||
//~^^ ERROR Ord
|
||||
//~^^^ ERROR binary operation
|
||||
//~^^^^ ERROR binary operation
|
||||
//~^^^^^ ERROR binary operation
|
||||
//~^^^^^^ ERROR binary operation
|
||||
@ -38,11 +37,10 @@ struct AllTheRanges {
|
||||
//~^^^^^^^^ ERROR binary operation
|
||||
//~^^^^^^^^^ ERROR binary operation
|
||||
//~^^^^^^^^^^ ERROR binary operation
|
||||
//~^^^^^^^^^^^ ERROR binary operation
|
||||
c: RangeFrom<usize>,
|
||||
//~^ ERROR PartialOrd
|
||||
//~^^ ERROR PartialOrd
|
||||
//~^^^ ERROR Ord
|
||||
//~^^ ERROR Ord
|
||||
//~^^^ ERROR binary operation
|
||||
//~^^^^ ERROR binary operation
|
||||
//~^^^^^ ERROR binary operation
|
||||
//~^^^^^^ ERROR binary operation
|
||||
@ -50,11 +48,10 @@ struct AllTheRanges {
|
||||
//~^^^^^^^^ ERROR binary operation
|
||||
//~^^^^^^^^^ ERROR binary operation
|
||||
//~^^^^^^^^^^ ERROR binary operation
|
||||
//~^^^^^^^^^^^ ERROR binary operation
|
||||
d: RangeFull,
|
||||
//~^ ERROR PartialOrd
|
||||
//~^^ ERROR PartialOrd
|
||||
//~^^^ ERROR Ord
|
||||
//~^^ ERROR Ord
|
||||
//~^^^ ERROR binary operation
|
||||
//~^^^^ ERROR binary operation
|
||||
//~^^^^^ ERROR binary operation
|
||||
//~^^^^^^ ERROR binary operation
|
||||
@ -62,11 +59,10 @@ struct AllTheRanges {
|
||||
//~^^^^^^^^ ERROR binary operation
|
||||
//~^^^^^^^^^ ERROR binary operation
|
||||
//~^^^^^^^^^^ ERROR binary operation
|
||||
//~^^^^^^^^^^^ ERROR binary operation
|
||||
e: RangeInclusive<usize>,
|
||||
//~^ ERROR PartialOrd
|
||||
//~^^ ERROR PartialOrd
|
||||
//~^^^ ERROR Ord
|
||||
//~^^ ERROR Ord
|
||||
//~^^^ ERROR binary operation
|
||||
//~^^^^ ERROR binary operation
|
||||
//~^^^^^ ERROR binary operation
|
||||
//~^^^^^^ ERROR binary operation
|
||||
@ -74,11 +70,10 @@ struct AllTheRanges {
|
||||
//~^^^^^^^^ ERROR binary operation
|
||||
//~^^^^^^^^^ ERROR binary operation
|
||||
//~^^^^^^^^^^ ERROR binary operation
|
||||
//~^^^^^^^^^^^ ERROR binary operation
|
||||
f: RangeToInclusive<usize>,
|
||||
//~^ ERROR PartialOrd
|
||||
//~^^ ERROR PartialOrd
|
||||
//~^^^ ERROR Ord
|
||||
//~^^ ERROR Ord
|
||||
//~^^^ ERROR binary operation
|
||||
//~^^^^ ERROR binary operation
|
||||
//~^^^^^ ERROR binary operation
|
||||
//~^^^^^^ ERROR binary operation
|
||||
@ -86,8 +81,6 @@ struct AllTheRanges {
|
||||
//~^^^^^^^^ ERROR binary operation
|
||||
//~^^^^^^^^^ ERROR binary operation
|
||||
//~^^^^^^^^^^ ERROR binary operation
|
||||
//~^^^^^^^^^^^ ERROR binary operation
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
||||
|
@ -15,8 +15,7 @@ fn mutate(s: &mut str) {
|
||||
//~^ ERROR `str: std::marker::Sized` is not satisfied
|
||||
//~| ERROR `str: std::marker::Sized` is not satisfied
|
||||
s[1usize] = bot();
|
||||
//~^ ERROR `str: std::ops::Index<usize>` is not satisfied
|
||||
//~| ERROR `str: std::ops::IndexMut<usize>` is not satisfied
|
||||
//~^ ERROR `str: std::ops::IndexMut<usize>` is not satisfied
|
||||
}
|
||||
|
||||
pub fn main() {}
|
||||
|
@ -21,13 +21,11 @@ fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
|
||||
fn a() {
|
||||
let x = call_it(&square, 22);
|
||||
//~^ ERROR E0277
|
||||
//~| ERROR E0277
|
||||
}
|
||||
|
||||
fn b() {
|
||||
let y = call_it_mut(&mut square, 22);
|
||||
//~^ ERROR E0277
|
||||
//~| ERROR E0277
|
||||
}
|
||||
|
||||
fn c() {
|
||||
|
@ -21,13 +21,11 @@ fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
|
||||
fn a() {
|
||||
let x = call_it(&square, 22);
|
||||
//~^ ERROR E0277
|
||||
//~| ERROR E0277
|
||||
}
|
||||
|
||||
fn b() {
|
||||
let y = call_it_mut(&mut square, 22);
|
||||
//~^ ERROR E0277
|
||||
//~| ERROR E0277
|
||||
}
|
||||
|
||||
fn c() {
|
||||
|
@ -22,13 +22,11 @@ fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
|
||||
fn a() {
|
||||
let x = call_it(&square, 22);
|
||||
//~^ ERROR E0277
|
||||
//~| ERROR E0277
|
||||
}
|
||||
|
||||
fn b() {
|
||||
let y = call_it_mut(&mut square, 22);
|
||||
//~^ ERROR E0277
|
||||
//~| ERROR E0277
|
||||
}
|
||||
|
||||
fn c() {
|
||||
|
@ -12,15 +12,15 @@
|
||||
|
||||
trait T {}
|
||||
|
||||
fn f1<X: ?Sized>(x: &X) {
|
||||
let _: X; // <-- this is OK, no bindings created, no initializer.
|
||||
fn f1<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized>(x: &X) {
|
||||
let _: W; // <-- this is OK, no bindings created, no initializer.
|
||||
let _: (isize, (X, isize)); //~ERROR `X: std::marker::Sized` is not satisfie
|
||||
let y: X; //~ERROR `X: std::marker::Sized` is not satisfied
|
||||
let y: (isize, (X, usize));
|
||||
let y: Y; //~ERROR `Y: std::marker::Sized` is not satisfied
|
||||
let y: (isize, (Z, usize)); //~ERROR `Z: std::marker::Sized` is not satisfied
|
||||
}
|
||||
fn f2<X: ?Sized + T>(x: &X) {
|
||||
fn f2<X: ?Sized, Y: ?Sized>(x: &X) {
|
||||
let y: X; //~ERROR `X: std::marker::Sized` is not satisfied
|
||||
let y: (isize, (X, isize)); //~ERROR `X: std::marker::Sized` is not satisfied
|
||||
let y: (isize, (Y, isize)); //~ERROR `Y: std::marker::Sized` is not satisfied
|
||||
}
|
||||
|
||||
fn f3<X: ?Sized>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
|
||||
|
@ -9,16 +9,5 @@ error[E0281]: type mismatch: `[closure@$DIR/E0281.rs:14:9: 14:24]` implements th
|
||||
|
|
||||
= note: required by `foo`
|
||||
|
||||
error[E0281]: type mismatch: `[closure@$DIR/E0281.rs:14:9: 14:24]` implements the trait `std::ops::FnOnce<(std::string::String,)>`, but the trait `std::ops::FnOnce<(usize,)>` is required
|
||||
--> $DIR/E0281.rs:14:5
|
||||
|
|
||||
14 | foo(|y: String| { });
|
||||
| ^^^ --------------- implements `std::ops::FnOnce<(std::string::String,)>`
|
||||
| |
|
||||
| requires `std::ops::FnOnce<(usize,)>`
|
||||
| expected usize, found struct `std::string::String`
|
||||
|
|
||||
= note: required by `foo`
|
||||
|
||||
error: aborting due to previous error(s)
|
||||
|
||||
|
@ -30,14 +30,6 @@ error[E0277]: the trait bound `{integer}: std::ops::Div<&str>` is not satisfied
|
||||
|
|
||||
= help: the trait `std::ops::Div<&str>` is not implemented for `{integer}`
|
||||
|
||||
error[E0277]: the trait bound `{integer}: std::cmp::PartialEq<std::string::String>` is not satisfied
|
||||
--> $DIR/binops.rs:16:7
|
||||
|
|
||||
16 | 5 < String::new();
|
||||
| ^ can't compare `{integer}` with `std::string::String`
|
||||
|
|
||||
= help: the trait `std::cmp::PartialEq<std::string::String>` is not implemented for `{integer}`
|
||||
|
||||
error[E0277]: the trait bound `{integer}: std::cmp::PartialOrd<std::string::String>` is not satisfied
|
||||
--> $DIR/binops.rs:16:7
|
||||
|
|
||||
|
@ -6,22 +6,6 @@ error[E0593]: closure takes 0 arguments but 2 arguments are required
|
||||
| |
|
||||
| expected closure that takes 2 arguments
|
||||
|
||||
error[E0593]: closure takes 0 arguments but 2 arguments are required
|
||||
--> $DIR/closure-arg-count.rs:12:15
|
||||
|
|
||||
12 | [1, 2, 3].sort_by(|| panic!());
|
||||
| ^^^^^^^ ----------- takes 0 arguments
|
||||
| |
|
||||
| expected closure that takes 2 arguments
|
||||
|
||||
error[E0593]: closure takes 1 argument but 2 arguments are required
|
||||
--> $DIR/closure-arg-count.rs:13:15
|
||||
|
|
||||
13 | [1, 2, 3].sort_by(|tuple| panic!());
|
||||
| ^^^^^^^ ---------------- takes 1 argument
|
||||
| |
|
||||
| expected closure that takes 2 arguments
|
||||
|
||||
error[E0593]: closure takes 1 argument but 2 arguments are required
|
||||
--> $DIR/closure-arg-count.rs:13:15
|
||||
|
|
||||
@ -47,13 +31,5 @@ error[E0593]: closure takes 1 argument but 2 arguments are required
|
||||
| |
|
||||
| expected closure that takes 2 arguments
|
||||
|
||||
error[E0593]: closure takes 1 argument but 2 arguments are required
|
||||
--> $DIR/closure-arg-count.rs:14:15
|
||||
|
|
||||
14 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
|
||||
| ^^^^^^^ -------------------------- takes 1 argument
|
||||
| |
|
||||
| expected closure that takes 2 arguments
|
||||
|
||||
error: aborting due to previous error(s)
|
||||
|
||||
|
@ -17,14 +17,5 @@ error[E0281]: type mismatch: `[closure@$DIR/issue-36053-2.rs:17:39: 17:53]` impl
|
||||
| requires `for<'r> std::ops::FnMut<(&'r &str,)>`
|
||||
| expected &str, found str
|
||||
|
||||
error[E0281]: type mismatch: `[closure@$DIR/issue-36053-2.rs:17:39: 17:53]` implements the trait `for<'r> std::ops::FnOnce<(&'r str,)>`, but the trait `for<'r> std::ops::FnOnce<(&'r &str,)>` is required
|
||||
--> $DIR/issue-36053-2.rs:17:32
|
||||
|
|
||||
17 | once::<&str>("str").fuse().filter(|a: &str| true).count();
|
||||
| ^^^^^^ -------------- implements `for<'r> std::ops::FnOnce<(&'r str,)>`
|
||||
| |
|
||||
| requires `for<'r> std::ops::FnOnce<(&'r &str,)>`
|
||||
| expected &str, found str
|
||||
|
||||
error: aborting due to previous error(s)
|
||||
|
||||
|
@ -24,7 +24,6 @@ pub fn main() {
|
||||
//~| NOTE implements
|
||||
let z = call_it(3, f);
|
||||
//~^ ERROR type mismatch
|
||||
//~| ERROR type mismatch
|
||||
//~| NOTE expected isize, found usize
|
||||
//~| NOTE expected isize, found usize
|
||||
//~| NOTE requires
|
||||
|
@ -12,19 +12,5 @@ error[E0281]: type mismatch: `[closure@$DIR/unboxed-closures-vtable-mismatch.rs:
|
||||
|
|
||||
= note: required by `call_it`
|
||||
|
||||
error[E0281]: type mismatch: `[closure@$DIR/unboxed-closures-vtable-mismatch.rs:22:23: 22:73]` implements the trait `std::ops::FnOnce<(usize, isize)>`, but the trait `std::ops::FnOnce<(isize, isize)>` is required
|
||||
--> $DIR/unboxed-closures-vtable-mismatch.rs:25:13
|
||||
|
|
||||
22 | let f = to_fn_mut(|x: usize, y: isize| -> isize { (x as isize) + y });
|
||||
| -------------------------------------------------- implements `std::ops::FnOnce<(usize, isize)>`
|
||||
...
|
||||
25 | let z = call_it(3, f);
|
||||
| ^^^^^^^
|
||||
| |
|
||||
| requires `std::ops::FnOnce<(isize, isize)>`
|
||||
| expected isize, found usize
|
||||
|
|
||||
= note: required by `call_it`
|
||||
|
||||
error: aborting due to previous error(s)
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
error[E0282]: type annotations needed
|
||||
error[E0283]: type annotations required: cannot resolve `&'a T: Foo`
|
||||
--> $DIR/issue-40294.rs:15:1
|
||||
|
|
||||
15 | / fn foo<'a,'b,T>(x: &'a T, y: &'b T)
|
||||
@ -8,7 +8,9 @@ error[E0282]: type annotations needed
|
||||
19 | | x.foo();
|
||||
20 | | y.foo();
|
||||
21 | | }
|
||||
| |_^ cannot infer type for `&'a T`
|
||||
| |_^
|
||||
|
|
||||
= note: required by `Foo`
|
||||
|
||||
error: aborting due to previous error(s)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user