diff options
| -rw-r--r-- | src/librustc/infer/outlives/bounds.rs | 2 | ||||
| -rw-r--r-- | src/librustc/traits/error_reporting.rs | 45 | ||||
| -rw-r--r-- | src/librustc/traits/mod.rs | 2 | ||||
| -rw-r--r-- | src/librustc_mir/transform/qualify_consts.rs | 2 | ||||
| -rw-r--r-- | src/librustc_typeck/check/coercion.rs | 2 | ||||
| -rw-r--r-- | src/librustc_typeck/check/compare_method.rs | 4 | ||||
| -rw-r--r-- | src/librustc_typeck/check/dropck.rs | 2 | ||||
| -rw-r--r-- | src/librustc_typeck/check/mod.rs | 27 | ||||
| -rw-r--r-- | src/librustc_typeck/check/op.rs | 2 | ||||
| -rw-r--r-- | src/librustc_typeck/coherence/builtin.rs | 2 | ||||
| -rw-r--r-- | src/librustc_typeck/lib.rs | 2 | ||||
| -rw-r--r-- | src/test/compile-fail/defaulted-never-note.rs | 41 |
12 files changed, 107 insertions, 26 deletions
diff --git a/src/librustc/infer/outlives/bounds.rs b/src/librustc/infer/outlives/bounds.rs index abb35d24d79..8bb3f4158ff 100644 --- a/src/librustc/infer/outlives/bounds.rs +++ b/src/librustc/infer/outlives/bounds.rs @@ -151,7 +151,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { // get solved *here*. match fulfill_cx.select_all_or_error(self) { Ok(()) => (), - Err(errors) => self.report_fulfillment_errors(&errors, None), + Err(errors) => self.report_fulfillment_errors(&errors, None, false), } implied_bounds diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 5d994a0e444..b19935b8c4f 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -47,7 +47,8 @@ use syntax_pos::{DUMMY_SP, Span}; impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn report_fulfillment_errors(&self, errors: &Vec<FulfillmentError<'tcx>>, - body_id: Option<hir::BodyId>) { + body_id: Option<hir::BodyId>, + fallback_has_occurred: bool) { #[derive(Debug)] struct ErrorDescriptor<'tcx> { predicate: ty::Predicate<'tcx>, @@ -107,7 +108,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { for (error, suppressed) in errors.iter().zip(is_suppressed) { if !suppressed { - self.report_fulfillment_error(error, body_id); + self.report_fulfillment_error(error, body_id, fallback_has_occurred); } } } @@ -151,11 +152,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>, - body_id: Option<hir::BodyId>) { + body_id: Option<hir::BodyId>, + fallback_has_occurred: bool) { debug!("report_fulfillment_errors({:?})", error); match error.code { FulfillmentErrorCode::CodeSelectionError(ref e) => { - self.report_selection_error(&error.obligation, e); + self.report_selection_error(&error.obligation, e, fallback_has_occurred); } FulfillmentErrorCode::CodeProjectionError(ref e) => { self.report_projection_error(&error.obligation, e); @@ -533,9 +535,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn report_selection_error(&self, obligation: &PredicateObligation<'tcx>, - error: &SelectionError<'tcx>) + error: &SelectionError<'tcx>, + fallback_has_occurred: bool) { let span = obligation.cause.span; + let _ = fallback_has_occurred; let mut err = match *error { SelectionError::Unimplemented => { @@ -619,6 +623,37 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.report_similar_impl_candidates(impl_candidates, &mut err); } + // If this error is due to `!: !Trait` but `(): Trait` then add a note + // about the fallback behaviour change. + if trait_predicate.skip_binder().self_ty().is_never() { + let predicate = trait_predicate.map_bound(|mut trait_pred| { + { + let trait_ref = &mut trait_pred.trait_ref; + let never_substs = trait_ref.substs; + let mut unit_substs = Vec::with_capacity(never_substs.len()); + unit_substs.push(self.tcx.mk_nil().into()); + unit_substs.extend(&never_substs[1..]); + trait_ref.substs = self.tcx.intern_substs(&unit_substs); + } + trait_pred + }); + let unit_obligation = Obligation { + cause: obligation.cause.clone(), + param_env: obligation.param_env, + recursion_depth: obligation.recursion_depth, + predicate, + }; + let mut selcx = SelectionContext::new(self); + if let Ok(Some(..)) = selcx.select(&unit_obligation) { + err.note("the trait is implemented for `()`. \ + Possibly this error has been caused by changes to \ + Rust's type-inference algorithm \ + (see: https://github.com/rust-lang/rust/issues/48950 \ + for more info). Consider whether you meant to use the \ + type `()` here instead."); + } + } + err } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index a2a5aa246cf..bd8f99780f9 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -580,7 +580,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ) { Ok(predicates) => predicates, Err(errors) => { - infcx.report_fulfillment_errors(&errors, None); + infcx.report_fulfillment_errors(&errors, None, false); // An unnormalized env is better than nothing. return elaborated_env; } diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 94446a98e63..59a872a23b0 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -1246,7 +1246,7 @@ impl MirPass for QualifyAndPromoteConstants { tcx.require_lang_item(lang_items::SyncTraitLangItem), cause); if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) { - infcx.report_fulfillment_errors(&err, None); + infcx.report_fulfillment_errors(&err, None, false); } }); } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 144ca37f2c6..269ee49f38e 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -571,7 +571,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // Object safety violations or miscellaneous. Err(err) => { - self.report_selection_error(&obligation, &err); + self.report_selection_error(&obligation, &err, false); // Treat this like an obligation and follow through // with the unsizing - the lack of a coercion should // be silent, as it causes a type mismatch later. diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index b6459b62410..60ac31ac8eb 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -334,7 +334,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) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) { - infcx.report_fulfillment_errors(errors, None); + infcx.report_fulfillment_errors(errors, None, false); return Err(ErrorReported); } @@ -839,7 +839,7 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Check that all obligations are satisfied by the implementation's // version. if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) { - infcx.report_fulfillment_errors(errors, None); + infcx.report_fulfillment_errors(errors, None, false); return; } diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 67c9832cbf9..596381d7ea6 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -112,7 +112,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) { // this could be reached when we get lazy normalization - infcx.report_fulfillment_errors(errors, None); + infcx.report_fulfillment_errors(errors, None, false); return Err(ErrorReported); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 80d95ea86e4..18de8d1bee7 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -873,11 +873,12 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; // All type checking constraints were added, try to fallback unsolved variables. - fcx.select_obligations_where_possible(); + fcx.select_obligations_where_possible(false); + let mut fallback_has_occurred = false; for ty in &fcx.unsolved_variables() { - fcx.fallback_if_possible(ty); + fallback_has_occurred |= fcx.fallback_if_possible(ty); } - fcx.select_obligations_where_possible(); + fcx.select_obligations_where_possible(fallback_has_occurred); // Even though coercion casts provide type hints, we check casts after fallback for // backwards compatibility. This makes fallback a stronger type hint than a cast coercion. @@ -1837,7 +1838,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // possible. This can help substantially when there are // indirect dependencies that don't seem worth tracking // precisely. - self.select_obligations_where_possible(); + self.select_obligations_where_possible(false); ty = self.resolve_type_vars_if_possible(&ty); debug!("resolve_type_vars_with_obligations: ty={:?}", ty); @@ -2154,7 +2155,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn resolve_generator_interiors(&self, def_id: DefId) { let mut generators = self.deferred_generator_interiors.borrow_mut(); for (body_id, interior) in generators.drain(..) { - self.select_obligations_where_possible(); + self.select_obligations_where_possible(false); generator_interior::resolve_interior(self, def_id, body_id, interior); } } @@ -2164,7 +2165,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // unconstrained floats with f64. // Fallback becomes very dubious if we have encountered type-checking errors. // In that case, fallback to TyError. - fn fallback_if_possible(&self, ty: Ty<'tcx>) { + // The return value indicates whether fallback has occured. + fn fallback_if_possible(&self, ty: Ty<'tcx>) -> bool { use rustc::ty::error::UnconstrainedNumeric::Neither; use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; @@ -2174,24 +2176,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { UnconstrainedInt => self.tcx.types.i32, UnconstrainedFloat => self.tcx.types.f64, Neither if self.type_var_diverges(ty) => self.tcx.types.never, - Neither => return + Neither => return false, }; debug!("default_type_parameters: defaulting `{:?}` to `{:?}`", ty, fallback); self.demand_eqtype(syntax_pos::DUMMY_SP, ty, fallback); + true } fn select_all_obligations_or_error(&self) { debug!("select_all_obligations_or_error"); if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) { - self.report_fulfillment_errors(&errors, self.inh.body_id); + self.report_fulfillment_errors(&errors, self.inh.body_id, false); } } /// Select as many obligations as we can at present. - fn select_obligations_where_possible(&self) { + fn select_obligations_where_possible(&self, fallback_has_occurred: bool) { match self.fulfillment_cx.borrow_mut().select_where_possible(self) { Ok(()) => { } - Err(errors) => { self.report_fulfillment_errors(&errors, self.inh.body_id); } + Err(errors) => { + self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred); + }, } } @@ -2595,7 +2600,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // an "opportunistic" vtable resolution of any trait bounds on // the call. This helps coercions. if check_closures { - self.select_obligations_where_possible(); + self.select_obligations_where_possible(false); } // For variadic functions, we don't have a declared type for all of diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 47a229cbd3b..eae692f4cda 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -479,7 +479,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match method { Some(ok) => { let method = self.register_infer_ok_obligations(ok); - self.select_obligations_where_possible(); + self.select_obligations_where_possible(false); Ok(method) } diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 2f1c42bbef8..9493c36fe95 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -386,7 +386,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Check that all transitive obligations are satisfied. if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) { - infcx.report_fulfillment_errors(&errors, None); + infcx.report_fulfillment_errors(&errors, None, false); } // Finally, resolve all regions. diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index a97c6e84eab..964c0021133 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -174,7 +174,7 @@ fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match fulfill_cx.select_all_or_error(infcx) { Ok(()) => true, Err(errors) => { - infcx.report_fulfillment_errors(&errors, None); + infcx.report_fulfillment_errors(&errors, None, false); false } } diff --git a/src/test/compile-fail/defaulted-never-note.rs b/src/test/compile-fail/defaulted-never-note.rs new file mode 100644 index 00000000000..798544f1649 --- /dev/null +++ b/src/test/compile-fail/defaulted-never-note.rs @@ -0,0 +1,41 @@ +// 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. + +#![allow(unused)] + +trait Deserialize: Sized { + fn deserialize() -> Result<Self, String>; +} + +impl Deserialize for () { + fn deserialize() -> Result<(), String> { + Ok(()) + } +} + +trait ImplementedForUnitButNotNever {} + +impl ImplementedForUnitButNotNever for () {} + +fn foo<T: ImplementedForUnitButNotNever>(_t: T) {} +//~^ NOTE required by `foo` + +fn smeg() { + let _x = return; + foo(_x); + //~^ ERROR the trait bound + //~| NOTE the trait `ImplementedForUnitButNotNever` is not implemented + //~| NOTE the trait is implemented for `()` +} + +fn main() { + smeg(); +} + |
