Skip to content

Commit fe2e427

Browse files
committed
wip: detect missing bounds when looking for methods
1 parent 03eb454 commit fe2e427

File tree

60 files changed

+658
-352
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+658
-352
lines changed

compiler/rustc_hir_typeck/src/expr.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1600,6 +1600,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16001600
if segment.ident.name == kw::Empty {
16011601
span_bug!(rcvr.span, "empty method name")
16021602
} else {
1603+
if let ty::Adt(def, _) = rcvr_t.kind() {
1604+
let t = self.tcx.at(expr.span).type_of(def.did()).instantiate_identity();
1605+
tracing::info!(?t);
1606+
let x =
1607+
self.lookup_method(t, segment, segment.ident.span, expr, rcvr, args);
1608+
tracing::info!("{x:#?}")
1609+
}
16031610
Err(self.report_method_error(expr.hir_id, rcvr_t, error, expected, false))
16041611
}
16051612
}

compiler/rustc_hir_typeck/src/method/probe.rs

+10
Original file line numberDiff line numberDiff line change
@@ -1757,6 +1757,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
17571757
) -> traits::SelectionResult<'tcx, traits::Selection<'tcx>> {
17581758
let obligation =
17591759
traits::Obligation::new(self.tcx, self.misc(self.span), self.param_env, trait_ref);
1760+
// HERE elaborate the obligation to get the failed ones.
17601761
traits::SelectionContext::new(self).select(&obligation)
17611762
}
17621763

@@ -1891,10 +1892,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
18911892
infer::FnCall,
18921893
poly_trait_ref,
18931894
);
1895+
tracing::info!(?trait_ref, "asdf");
18941896
let trait_ref = ocx.normalize(cause, self.param_env, trait_ref);
1897+
tracing::info!(?trait_ref, "2asdf");
18951898
(xform_self_ty, xform_ret_ty) =
18961899
self.xform_self_ty(probe.item, trait_ref.self_ty(), trait_ref.args);
18971900
xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty);
1901+
tracing::info!(?xform_self_ty);
18981902
match self_ty.kind() {
18991903
// HACK: opaque types will match anything for which their bounds hold.
19001904
// Thus we need to prevent them from trying to match the `&_` autoref
@@ -1944,6 +1948,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
19441948
));
19451949
}
19461950
}
1951+
} else {
1952+
possibly_unsatisfied_predicates.push((
1953+
self.resolve_vars_if_possible(obligation.predicate),
1954+
None,
1955+
Some(obligation.cause),
1956+
))
19471957
}
19481958
}
19491959

compiler/rustc_hir_typeck/src/method/suggest.rs

+25
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
583583
}
584584
}
585585

586+
#[tracing::instrument(skip(self), level = "info")]
586587
fn report_no_match_method_error(
587588
&self,
588589
mut span: Span,
@@ -744,6 +745,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
744745
ty_str = short_ty_str;
745746
}
746747

748+
// if let ty::Adt(def, _) = rcvr_ty.kind() {
749+
// let ty = self.tcx.at(span).type_of(def.did()).instantiate_identity();
750+
// let autoderef = self.autoderef(span, ty).silence_errors();
751+
// // let candidate_found = autoderef.any(|(ty, _)| {
752+
// // if let ty::Adt(adt_def, _) = ty.kind() {
753+
// // self.tcx
754+
// // .inherent_impls(adt_def.did())
755+
// // .into_iter()
756+
// // .any(|def_id| self.associated_value(*def_id, item_name).is_some())
757+
// // } else {
758+
// // false
759+
// // }
760+
// // });
761+
// for x in autoderef {
762+
// err.note(format!("{x:#?}"));
763+
// }
764+
// // let has_deref = autoderef.step_count() > 0;
765+
// // if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() {
766+
// // if let Some((path_string, _)) = ty_str.split_once('<') {
767+
// // ty_str_reported = path_string.to_string();
768+
// // }
769+
// // }
770+
// }
771+
747772
if rcvr_ty.references_error() {
748773
err.downgrade_to_delayed_bug();
749774
}

compiler/rustc_middle/src/traits/select.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ pub enum EvaluationResult {
208208
/// stack results.
209209
EvaluatedToAmbigStackDependent,
210210
/// Evaluation failed.
211-
EvaluatedToErr,
211+
EvaluatedToErr(u32),
212212
}
213213

214214
impl EvaluationResult {
@@ -232,7 +232,7 @@ impl EvaluationResult {
232232
| EvaluatedToAmbig
233233
| EvaluatedToAmbigStackDependent => true,
234234

235-
EvaluatedToErr => false,
235+
EvaluatedToErr(_) => false,
236236
}
237237
}
238238

@@ -244,7 +244,7 @@ impl EvaluationResult {
244244
| EvaluatedToOk
245245
| EvaluatedToOkModuloRegions
246246
| EvaluatedToAmbig
247-
| EvaluatedToErr => false,
247+
| EvaluatedToErr(_) => false,
248248
}
249249
}
250250
}

compiler/rustc_trait_selection/src/infer.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ impl<'tcx> InferCtxt<'tcx> {
101101
recursion_depth: 0,
102102
predicate: trait_ref.upcast(self.tcx),
103103
};
104-
self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr)
104+
self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr(0))
105105
}
106106

107107
/// Returns `Some` if a type implements a trait shallowly, without side-effects,

compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl<'tcx> InferCtxt<'tcx> {
7474
let mut result = EvaluationResult::EvaluatedToOk;
7575
for error in ocx.select_all_or_error() {
7676
if error.is_true_error() {
77-
return Ok(EvaluationResult::EvaluatedToErr);
77+
return Ok(EvaluationResult::EvaluatedToErr(1));
7878
} else {
7979
result = result.max(EvaluationResult::EvaluatedToAmbig);
8080
}
@@ -116,10 +116,10 @@ impl<'tcx> InferCtxt<'tcx> {
116116
r,
117117
)
118118
}
119-
OverflowError::Error(_) => EvaluationResult::EvaluatedToErr,
119+
OverflowError::Error(_) => EvaluationResult::EvaluatedToErr(2),
120120
})
121121
}
122-
Err(OverflowError::Error(_)) => EvaluationResult::EvaluatedToErr,
122+
Err(OverflowError::Error(_)) => EvaluationResult::EvaluatedToErr(3),
123123
}
124124
}
125125
}

compiler/rustc_trait_selection/src/traits/select/mod.rs

+31-22
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
539539

540540
match self.infcx.leak_check(outer_universe, Some(snapshot)) {
541541
Ok(()) => {}
542-
Err(_) => return Ok(EvaluatedToErr),
542+
Err(_) => return Ok(EvaluatedToErr(4)),
543543
}
544544

545545
if self.infcx.opaque_types_added_in_snapshot(snapshot) {
@@ -571,10 +571,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
571571
for mut obligation in predicates {
572572
obligation.set_depth_from_parent(stack.depth());
573573
let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?;
574-
if let EvaluatedToErr = eval {
574+
if let EvaluatedToErr(_) = eval {
575575
// fast-path - EvaluatedToErr is the top of the lattice,
576576
// so we don't need to look on the other predicates.
577-
return Ok(EvaluatedToErr);
577+
return Ok(EvaluatedToErr(5));
578578
} else {
579579
result = cmp::max(result, eval);
580580
}
@@ -603,8 +603,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
603603
None => self.check_recursion_limit(&obligation, &obligation)?,
604604
}
605605

606-
ensure_sufficient_stack(|| {
606+
let x = ensure_sufficient_stack(|| {
607607
let bound_predicate = obligation.predicate.kind();
608+
tracing::info!(?bound_predicate, "zxcv");
608609
match bound_predicate.skip_binder() {
609610
ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => {
610611
let t = bound_predicate.rebind(t);
@@ -623,7 +624,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
623624
self.evaluate_predicates_recursively(previous_stack, nested)
624625
}
625626
Err(effects::EvaluationFailure::Ambiguous) => Ok(EvaluatedToAmbig),
626-
Err(effects::EvaluationFailure::NoSolution) => Ok(EvaluatedToErr),
627+
Err(effects::EvaluationFailure::NoSolution) => Ok(EvaluatedToErr(6)),
627628
}
628629
})
629630
}
@@ -635,7 +636,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
635636
Ok(Ok(InferOk { obligations, .. })) => {
636637
self.evaluate_predicates_recursively(previous_stack, obligations)
637638
}
638-
Ok(Err(_)) => Ok(EvaluatedToErr),
639+
Ok(Err(_)) => Ok(EvaluatedToErr(7)),
639640
Err(..) => Ok(EvaluatedToAmbig),
640641
}
641642
}
@@ -647,7 +648,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
647648
Ok(Ok(InferOk { obligations, .. })) => {
648649
self.evaluate_predicates_recursively(previous_stack, obligations)
649650
}
650-
Ok(Err(_)) => Ok(EvaluatedToErr),
651+
Ok(Err(_)) => Ok(EvaluatedToErr(8)),
651652
Err(..) => Ok(EvaluatedToAmbig),
652653
}
653654
}
@@ -760,7 +761,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
760761
if self.tcx().is_dyn_compatible(trait_def_id) {
761762
Ok(EvaluatedToOk)
762763
} else {
763-
Ok(EvaluatedToErr)
764+
Ok(EvaluatedToErr(9))
764765
}
765766
}
766767

@@ -827,7 +828,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
827828
}
828829
ProjectAndUnifyResult::FailedNormalization => Ok(EvaluatedToAmbig),
829830
ProjectAndUnifyResult::Recursive => Ok(EvaluatedToAmbigStackDependent),
830-
ProjectAndUnifyResult::MismatchedProjectionTypes(_) => Ok(EvaluatedToErr),
831+
ProjectAndUnifyResult::MismatchedProjectionTypes(_) => {
832+
Ok(EvaluatedToErr(10))
833+
}
831834
}
832835
}
833836

@@ -840,8 +843,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
840843
) {
841844
Ok(()) => Ok(EvaluatedToOk),
842845
Err(NotConstEvaluatable::MentionsInfer) => Ok(EvaluatedToAmbig),
843-
Err(NotConstEvaluatable::MentionsParam) => Ok(EvaluatedToErr),
844-
Err(_) => Ok(EvaluatedToErr),
846+
Err(NotConstEvaluatable::MentionsParam) => Ok(EvaluatedToErr(11)),
847+
Err(_) => Ok(EvaluatedToErr(12)),
845848
}
846849
}
847850

@@ -929,20 +932,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
929932
previous_stack,
930933
inf_ok.into_obligations(),
931934
),
932-
Err(_) => Ok(EvaluatedToErr),
935+
Err(_) => Ok(EvaluatedToErr(13)),
933936
}
934937
}
935938
(Err(EvaluateConstErr::InvalidConstParamTy(..)), _)
936-
| (_, Err(EvaluateConstErr::InvalidConstParamTy(..))) => Ok(EvaluatedToErr),
939+
| (_, Err(EvaluateConstErr::InvalidConstParamTy(..))) => {
940+
Ok(EvaluatedToErr(14))
941+
}
937942
(Err(EvaluateConstErr::EvaluationFailure(..)), _)
938-
| (_, Err(EvaluateConstErr::EvaluationFailure(..))) => Ok(EvaluatedToErr),
943+
| (_, Err(EvaluateConstErr::EvaluationFailure(..))) => {
944+
Ok(EvaluatedToErr(15))
945+
}
939946
(Err(EvaluateConstErr::HasGenericsOrInfers), _)
940947
| (_, Err(EvaluateConstErr::HasGenericsOrInfers)) => {
941948
if c1.has_non_region_infer() || c2.has_non_region_infer() {
942949
Ok(EvaluatedToAmbig)
943950
} else {
944951
// Two different constants using generic parameters ~> error.
945-
Ok(EvaluatedToErr)
952+
Ok(EvaluatedToErr(16))
946953
}
947954
}
948955
}
@@ -986,11 +993,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
986993
previous_stack,
987994
inf_ok.into_obligations(),
988995
),
989-
Err(_) => Ok(EvaluatedToErr),
996+
Err(_) => Ok(EvaluatedToErr(17)),
990997
}
991998
}
992999
}
993-
})
1000+
});
1001+
x
9941002
}
9951003

9961004
#[instrument(skip(self, previous_stack), level = "debug", ret)]
@@ -1048,7 +1056,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10481056
// normalize these obligations before evaluating.
10491057
// so we will try to normalize the obligation and evaluate again.
10501058
// we will replace it with new solver in the future.
1051-
if EvaluationResult::EvaluatedToErr == result
1059+
if let EvaluationResult::EvaluatedToErr(_) = result
10521060
&& fresh_trait_pred.has_aliases()
10531061
&& fresh_trait_pred.is_global()
10541062
{
@@ -1216,7 +1224,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
12161224
Ok(Some(c)) => self.evaluate_candidate(stack, &c),
12171225
Ok(None) => Ok(EvaluatedToAmbig),
12181226
Err(Overflow(OverflowError::Canonical)) => Err(OverflowError::Canonical),
1219-
Err(..) => Ok(EvaluatedToErr),
1227+
Err(..) => Ok(EvaluatedToErr(20)),
12201228
}
12211229
}
12221230

@@ -1264,7 +1272,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
12641272
selection.nested_obligations().into_iter(),
12651273
)
12661274
}
1267-
Err(..) => Ok(EvaluatedToErr),
1275+
Err(..) => Ok(EvaluatedToErr(21)),
12681276
}
12691277
})?;
12701278

@@ -1697,7 +1705,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16971705
self.evaluation_probe(|this| {
16981706
match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) {
16991707
Ok(obligations) => this.evaluate_predicates_recursively(stack.list(), obligations),
1700-
Err(()) => Ok(EvaluatedToErr),
1708+
Err(()) => Ok(EvaluatedToErr(22)),
17011709
}
17021710
})
17031711
}
@@ -2951,6 +2959,7 @@ impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> {
29512959
/// provisional results added from the subtree that encountered the
29522960
/// error. When we pop the node at `reached_depth` from the stack, we
29532961
/// can commit all the things that remain in the provisional cache.
2962+
#[derive(Debug)]
29542963
struct ProvisionalEvaluationCache<'tcx> {
29552964
/// next "depth first number" to issue -- just a counter
29562965
dfn: Cell<usize>,
@@ -3128,7 +3137,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
31283137
}
31293138
}
31303139

3131-
#[derive(Copy, Clone)]
3140+
#[derive(Copy, Clone, Debug)]
31323141
struct TraitObligationStackList<'o, 'tcx> {
31333142
cache: &'o ProvisionalEvaluationCache<'tcx>,
31343143
head: Option<&'o TraitObligationStack<'o, 'tcx>>,

tests/ui/associated-consts/associated-const-no-item.stderr

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1-
error[E0599]: no associated item named `ID` found for type `i32` in the current scope
1+
error[E0599]: the associated item `ID` exists for type `i32`, but its trait bounds were not satisfied
22
--> $DIR/associated-const-no-item.rs:5:23
33
|
44
LL | const X: i32 = <i32>::ID;
5-
| ^^ associated item not found in `i32`
5+
| ^^ associated item cannot be called on `i32` due to unsatisfied trait bounds
66
|
7+
= note: the following trait bounds were not satisfied:
8+
`i32: Foo`
9+
`&i32: Foo`
10+
`&mut i32: Foo`
711
= help: items from traits can only be used if the trait is implemented and in scope
812
note: `Foo` defines an item `ID`, perhaps you need to implement it
913
--> $DIR/associated-const-no-item.rs:1:1

tests/ui/associated-types/issue-43924.stderr

+7-2
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,16 @@ note: required by a bound in `Foo::Out`
1010
LL | type Out: Default + ToString + ?Sized = dyn ToString;
1111
| ^^^^^^^ required by this bound in `Foo::Out`
1212

13-
error[E0599]: no function or associated item named `default` found for trait object `(dyn ToString + 'static)` in the current scope
13+
error[E0599]: the function or associated item `default` exists for trait object `dyn ToString`, but its trait bounds were not satisfied
1414
--> $DIR/issue-43924.rs:14:39
1515
|
1616
LL | assert_eq!(<() as Foo<u32>>::Out::default().to_string(), "false");
17-
| ^^^^^^^ function or associated item not found in `dyn ToString`
17+
| ^^^^^^^ function or associated item cannot be called on `dyn ToString` due to unsatisfied trait bounds
18+
|
19+
= note: the following trait bounds were not satisfied:
20+
`(dyn ToString + 'static): Default`
21+
`&(dyn ToString + 'static): Default`
22+
`&mut (dyn ToString + 'static): Default`
1823

1924
error: aborting due to 2 previous errors
2025

0 commit comments

Comments
 (0)