Skip to content

Commit 5b32211

Browse files
committed
Add note about fallback to !: !Trait error
1 parent 5a6b781 commit 5b32211

File tree

12 files changed

+107
-26
lines changed

12 files changed

+107
-26
lines changed

src/librustc/infer/outlives/bounds.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
151151
// get solved *here*.
152152
match fulfill_cx.select_all_or_error(self) {
153153
Ok(()) => (),
154-
Err(errors) => self.report_fulfillment_errors(&errors, None),
154+
Err(errors) => self.report_fulfillment_errors(&errors, None, false),
155155
}
156156

157157
implied_bounds

src/librustc/traits/error_reporting.rs

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ use syntax_pos::{DUMMY_SP, Span};
4747
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
4848
pub fn report_fulfillment_errors(&self,
4949
errors: &Vec<FulfillmentError<'tcx>>,
50-
body_id: Option<hir::BodyId>) {
50+
body_id: Option<hir::BodyId>,
51+
fallback_has_occurred: bool) {
5152
#[derive(Debug)]
5253
struct ErrorDescriptor<'tcx> {
5354
predicate: ty::Predicate<'tcx>,
@@ -107,7 +108,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
107108

108109
for (error, suppressed) in errors.iter().zip(is_suppressed) {
109110
if !suppressed {
110-
self.report_fulfillment_error(error, body_id);
111+
self.report_fulfillment_error(error, body_id, fallback_has_occurred);
111112
}
112113
}
113114
}
@@ -151,11 +152,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
151152
}
152153

153154
fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>,
154-
body_id: Option<hir::BodyId>) {
155+
body_id: Option<hir::BodyId>,
156+
fallback_has_occurred: bool) {
155157
debug!("report_fulfillment_errors({:?})", error);
156158
match error.code {
157159
FulfillmentErrorCode::CodeSelectionError(ref e) => {
158-
self.report_selection_error(&error.obligation, e);
160+
self.report_selection_error(&error.obligation, e, fallback_has_occurred);
159161
}
160162
FulfillmentErrorCode::CodeProjectionError(ref e) => {
161163
self.report_projection_error(&error.obligation, e);
@@ -533,9 +535,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
533535

534536
pub fn report_selection_error(&self,
535537
obligation: &PredicateObligation<'tcx>,
536-
error: &SelectionError<'tcx>)
538+
error: &SelectionError<'tcx>,
539+
fallback_has_occurred: bool)
537540
{
538541
let span = obligation.cause.span;
542+
let _ = fallback_has_occurred;
539543

540544
let mut err = match *error {
541545
SelectionError::Unimplemented => {
@@ -619,6 +623,37 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
619623
self.report_similar_impl_candidates(impl_candidates, &mut err);
620624
}
621625

626+
// If this error is due to `!: !Trait` but `(): Trait` then add a note
627+
// about the fallback behaviour change.
628+
if trait_predicate.skip_binder().self_ty().is_never() {
629+
let predicate = trait_predicate.map_bound(|mut trait_pred| {
630+
{
631+
let trait_ref = &mut trait_pred.trait_ref;
632+
let never_substs = trait_ref.substs;
633+
let mut unit_substs = Vec::with_capacity(never_substs.len());
634+
unit_substs.push(self.tcx.mk_nil().into());
635+
unit_substs.extend(&never_substs[1..]);
636+
trait_ref.substs = self.tcx.intern_substs(&unit_substs);
637+
}
638+
trait_pred
639+
});
640+
let unit_obligation = Obligation {
641+
cause: obligation.cause.clone(),
642+
param_env: obligation.param_env,
643+
recursion_depth: obligation.recursion_depth,
644+
predicate,
645+
};
646+
let mut selcx = SelectionContext::new(self);
647+
if let Ok(Some(..)) = selcx.select(&unit_obligation) {
648+
err.note("the trait is implemented for `()`. \
649+
Possibly this error has been caused by changes to \
650+
Rust's type-inference algorithm \
651+
(see: https://github.com/rust-lang/rust/issues/48950 \
652+
for more info). Consider whether you meant to use the \
653+
type `()` here instead.");
654+
}
655+
}
656+
622657
err
623658
}
624659

src/librustc/traits/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
580580
) {
581581
Ok(predicates) => predicates,
582582
Err(errors) => {
583-
infcx.report_fulfillment_errors(&errors, None);
583+
infcx.report_fulfillment_errors(&errors, None, false);
584584
// An unnormalized env is better than nothing.
585585
return elaborated_env;
586586
}

src/librustc_mir/transform/qualify_consts.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1246,7 +1246,7 @@ impl MirPass for QualifyAndPromoteConstants {
12461246
tcx.require_lang_item(lang_items::SyncTraitLangItem),
12471247
cause);
12481248
if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
1249-
infcx.report_fulfillment_errors(&err, None);
1249+
infcx.report_fulfillment_errors(&err, None, false);
12501250
}
12511251
});
12521252
}

src/librustc_typeck/check/coercion.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
571571

572572
// Object safety violations or miscellaneous.
573573
Err(err) => {
574-
self.report_selection_error(&obligation, &err);
574+
self.report_selection_error(&obligation, &err, false);
575575
// Treat this like an obligation and follow through
576576
// with the unsizing - the lack of a coercion should
577577
// be silent, as it causes a type mismatch later.

src/librustc_typeck/check/compare_method.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
334334
// Check that all obligations are satisfied by the implementation's
335335
// version.
336336
if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
337-
infcx.report_fulfillment_errors(errors, None);
337+
infcx.report_fulfillment_errors(errors, None, false);
338338
return Err(ErrorReported);
339339
}
340340

@@ -839,7 +839,7 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
839839
// Check that all obligations are satisfied by the implementation's
840840
// version.
841841
if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
842-
infcx.report_fulfillment_errors(errors, None);
842+
infcx.report_fulfillment_errors(errors, None, false);
843843
return;
844844
}
845845

src/librustc_typeck/check/dropck.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
112112

113113
if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) {
114114
// this could be reached when we get lazy normalization
115-
infcx.report_fulfillment_errors(errors, None);
115+
infcx.report_fulfillment_errors(errors, None, false);
116116
return Err(ErrorReported);
117117
}
118118

src/librustc_typeck/check/mod.rs

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -873,11 +873,12 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
873873
};
874874

875875
// All type checking constraints were added, try to fallback unsolved variables.
876-
fcx.select_obligations_where_possible();
876+
fcx.select_obligations_where_possible(false);
877+
let mut fallback_has_occurred = false;
877878
for ty in &fcx.unsolved_variables() {
878-
fcx.fallback_if_possible(ty);
879+
fallback_has_occurred |= fcx.fallback_if_possible(ty);
879880
}
880-
fcx.select_obligations_where_possible();
881+
fcx.select_obligations_where_possible(fallback_has_occurred);
881882

882883
// Even though coercion casts provide type hints, we check casts after fallback for
883884
// 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> {
18371838
// possible. This can help substantially when there are
18381839
// indirect dependencies that don't seem worth tracking
18391840
// precisely.
1840-
self.select_obligations_where_possible();
1841+
self.select_obligations_where_possible(false);
18411842
ty = self.resolve_type_vars_if_possible(&ty);
18421843

18431844
debug!("resolve_type_vars_with_obligations: ty={:?}", ty);
@@ -2154,7 +2155,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
21542155
fn resolve_generator_interiors(&self, def_id: DefId) {
21552156
let mut generators = self.deferred_generator_interiors.borrow_mut();
21562157
for (body_id, interior) in generators.drain(..) {
2157-
self.select_obligations_where_possible();
2158+
self.select_obligations_where_possible(false);
21582159
generator_interior::resolve_interior(self, def_id, body_id, interior);
21592160
}
21602161
}
@@ -2164,7 +2165,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
21642165
// unconstrained floats with f64.
21652166
// Fallback becomes very dubious if we have encountered type-checking errors.
21662167
// In that case, fallback to TyError.
2167-
fn fallback_if_possible(&self, ty: Ty<'tcx>) {
2168+
// The return value indicates whether fallback has occured.
2169+
fn fallback_if_possible(&self, ty: Ty<'tcx>) -> bool {
21682170
use rustc::ty::error::UnconstrainedNumeric::Neither;
21692171
use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat};
21702172

@@ -2174,24 +2176,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
21742176
UnconstrainedInt => self.tcx.types.i32,
21752177
UnconstrainedFloat => self.tcx.types.f64,
21762178
Neither if self.type_var_diverges(ty) => self.tcx.types.never,
2177-
Neither => return
2179+
Neither => return false,
21782180
};
21792181
debug!("default_type_parameters: defaulting `{:?}` to `{:?}`", ty, fallback);
21802182
self.demand_eqtype(syntax_pos::DUMMY_SP, ty, fallback);
2183+
true
21812184
}
21822185

21832186
fn select_all_obligations_or_error(&self) {
21842187
debug!("select_all_obligations_or_error");
21852188
if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) {
2186-
self.report_fulfillment_errors(&errors, self.inh.body_id);
2189+
self.report_fulfillment_errors(&errors, self.inh.body_id, false);
21872190
}
21882191
}
21892192

21902193
/// Select as many obligations as we can at present.
2191-
fn select_obligations_where_possible(&self) {
2194+
fn select_obligations_where_possible(&self, fallback_has_occurred: bool) {
21922195
match self.fulfillment_cx.borrow_mut().select_where_possible(self) {
21932196
Ok(()) => { }
2194-
Err(errors) => { self.report_fulfillment_errors(&errors, self.inh.body_id); }
2197+
Err(errors) => {
2198+
self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred);
2199+
},
21952200
}
21962201
}
21972202

@@ -2595,7 +2600,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
25952600
// an "opportunistic" vtable resolution of any trait bounds on
25962601
// the call. This helps coercions.
25972602
if check_closures {
2598-
self.select_obligations_where_possible();
2603+
self.select_obligations_where_possible(false);
25992604
}
26002605

26012606
// For variadic functions, we don't have a declared type for all of

src/librustc_typeck/check/op.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
479479
match method {
480480
Some(ok) => {
481481
let method = self.register_infer_ok_obligations(ok);
482-
self.select_obligations_where_possible();
482+
self.select_obligations_where_possible(false);
483483

484484
Ok(method)
485485
}

src/librustc_typeck/coherence/builtin.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
386386

387387
// Check that all transitive obligations are satisfied.
388388
if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) {
389-
infcx.report_fulfillment_errors(&errors, None);
389+
infcx.report_fulfillment_errors(&errors, None, false);
390390
}
391391

392392
// Finally, resolve all regions.

src/librustc_typeck/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
174174
match fulfill_cx.select_all_or_error(infcx) {
175175
Ok(()) => true,
176176
Err(errors) => {
177-
infcx.report_fulfillment_errors(&errors, None);
177+
infcx.report_fulfillment_errors(&errors, None, false);
178178
false
179179
}
180180
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![allow(unused)]
12+
13+
trait Deserialize: Sized {
14+
fn deserialize() -> Result<Self, String>;
15+
}
16+
17+
impl Deserialize for () {
18+
fn deserialize() -> Result<(), String> {
19+
Ok(())
20+
}
21+
}
22+
23+
trait ImplementedForUnitButNotNever {}
24+
25+
impl ImplementedForUnitButNotNever for () {}
26+
27+
fn foo<T: ImplementedForUnitButNotNever>(_t: T) {}
28+
//~^ NOTE required by `foo`
29+
30+
fn smeg() {
31+
let _x = return;
32+
foo(_x);
33+
//~^ ERROR the trait bound
34+
//~| NOTE the trait `ImplementedForUnitButNotNever` is not implemented
35+
//~| NOTE the trait is implemented for `()`
36+
}
37+
38+
fn main() {
39+
smeg();
40+
}
41+

0 commit comments

Comments
 (0)