Skip to content

Commit 6cfe52c

Browse files
committed
Gracefully fail to resolve associated items instead of delay_span_bug.
1 parent 532be94 commit 6cfe52c

File tree

11 files changed

+99
-87
lines changed

11 files changed

+99
-87
lines changed

compiler/rustc_middle/src/query/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1145,7 +1145,7 @@ rustc_queries! {
11451145

11461146
query codegen_fulfill_obligation(
11471147
key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)
1148-
) -> Result<&'tcx ImplSource<'tcx, ()>, ErrorGuaranteed> {
1148+
) -> Result<&'tcx ImplSource<'tcx, ()>, traits::CodegenObligationError> {
11491149
cache_on_disk_if { true }
11501150
desc { |tcx|
11511151
"checking if `{}` fulfills its obligations",

compiler/rustc_middle/src/traits/mod.rs

+18
Original file line numberDiff line numberDiff line change
@@ -963,3 +963,21 @@ pub enum MethodViolationCode {
963963
/// the method's receiver (`self` argument) can't be dispatched on
964964
UndispatchableReceiver,
965965
}
966+
967+
/// These are the error cases for `codegen_fulfill_obligation`.
968+
#[derive(Copy, Clone, Debug, Hash, HashStable, Encodable, Decodable)]
969+
pub enum CodegenObligationError {
970+
/// Ambiguity can happen when monomorphizing during trans
971+
/// expands to some humongous type that never occurred
972+
/// statically -- this humongous type can then overflow,
973+
/// leading to an ambiguous result. So report this as an
974+
/// overflow bug, since I believe this is the only case
975+
/// where ambiguity can result.
976+
Ambiguity,
977+
/// This can trigger when we probe for the source of a `'static` lifetime requirement
978+
/// on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound.
979+
/// This can also trigger when we have a global bound that is not actually satisfied,
980+
/// but was included during typeck due to the trivial_bounds feature.
981+
Unimplemented,
982+
FulfillmentError,
983+
}

compiler/rustc_trait_selection/src/traits/codegen.rs

+16-75
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@
33
// seems likely that they should eventually be merged into more
44
// general routines.
55

6-
use crate::infer::{InferCtxt, TyCtxtInferExt};
6+
use crate::infer::TyCtxtInferExt;
77
use crate::traits::{
88
FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine,
99
Unimplemented,
1010
};
11-
use rustc_errors::ErrorGuaranteed;
12-
use rustc_middle::ty::fold::TypeFoldable;
11+
use rustc_middle::traits::CodegenObligationError;
1312
use rustc_middle::ty::{self, TyCtxt};
1413

1514
/// Attempts to resolve an obligation to an `ImplSource`. The result is
@@ -23,7 +22,7 @@ use rustc_middle::ty::{self, TyCtxt};
2322
pub fn codegen_fulfill_obligation<'tcx>(
2423
tcx: TyCtxt<'tcx>,
2524
(param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
26-
) -> Result<&'tcx ImplSource<'tcx, ()>, ErrorGuaranteed> {
25+
) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> {
2726
// Remove any references to regions; this helps improve caching.
2827
let trait_ref = tcx.erase_regions(trait_ref);
2928
// We expect the input to be fully normalized.
@@ -40,37 +39,8 @@ pub fn codegen_fulfill_obligation<'tcx>(
4039

4140
let selection = match selcx.select(&obligation) {
4241
Ok(Some(selection)) => selection,
43-
Ok(None) => {
44-
// Ambiguity can happen when monomorphizing during trans
45-
// expands to some humongous type that never occurred
46-
// statically -- this humongous type can then overflow,
47-
// leading to an ambiguous result. So report this as an
48-
// overflow bug, since I believe this is the only case
49-
// where ambiguity can result.
50-
let reported = infcx.tcx.sess.delay_span_bug(
51-
rustc_span::DUMMY_SP,
52-
&format!(
53-
"encountered ambiguity selecting `{:?}` during codegen, presuming due to \
54-
overflow or prior type error",
55-
trait_ref
56-
),
57-
);
58-
return Err(reported);
59-
}
60-
Err(Unimplemented) => {
61-
// This can trigger when we probe for the source of a `'static` lifetime requirement
62-
// on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound.
63-
// This can also trigger when we have a global bound that is not actually satisfied,
64-
// but was included during typeck due to the trivial_bounds feature.
65-
let guar = infcx.tcx.sess.delay_span_bug(
66-
rustc_span::DUMMY_SP,
67-
&format!(
68-
"Encountered error `Unimplemented` selecting `{:?}` during codegen",
69-
trait_ref
70-
),
71-
);
72-
return Err(guar);
73-
}
42+
Ok(None) => return Err(CodegenObligationError::Ambiguity),
43+
Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented),
7444
Err(e) => {
7545
bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
7646
}
@@ -85,7 +55,17 @@ pub fn codegen_fulfill_obligation<'tcx>(
8555
let impl_source = selection.map(|predicate| {
8656
fulfill_cx.register_predicate_obligation(&infcx, predicate);
8757
});
88-
let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, impl_source);
58+
59+
// In principle, we only need to do this so long as `impl_source`
60+
// contains unbound type parameters. It could be a slight
61+
// optimization to stop iterating early.
62+
let errors = fulfill_cx.select_all_or_error(&infcx);
63+
if !errors.is_empty() {
64+
return Err(CodegenObligationError::FulfillmentError);
65+
}
66+
67+
let impl_source = infcx.resolve_vars_if_possible(impl_source);
68+
let impl_source = infcx.tcx.erase_regions(impl_source);
8969

9070
// Opaque types may have gotten their hidden types constrained, but we can ignore them safely
9171
// as they will get constrained elsewhere, too.
@@ -95,42 +75,3 @@ pub fn codegen_fulfill_obligation<'tcx>(
9575
Ok(&*tcx.arena.alloc(impl_source))
9676
})
9777
}
98-
99-
// # Global Cache
100-
101-
/// Finishes processes any obligations that remain in the
102-
/// fulfillment context, and then returns the result with all type
103-
/// variables removed and regions erased. Because this is intended
104-
/// for use outside of type inference, if any errors occur,
105-
/// it will panic. It is used during normalization and other cases
106-
/// where processing the obligations in `fulfill_cx` may cause
107-
/// type inference variables that appear in `result` to be
108-
/// unified, and hence we need to process those obligations to get
109-
/// the complete picture of the type.
110-
fn drain_fulfillment_cx_or_panic<'tcx, T>(
111-
infcx: &InferCtxt<'_, 'tcx>,
112-
fulfill_cx: &mut FulfillmentContext<'tcx>,
113-
result: T,
114-
) -> T
115-
where
116-
T: TypeFoldable<'tcx>,
117-
{
118-
debug!("drain_fulfillment_cx_or_panic()");
119-
120-
// In principle, we only need to do this so long as `result`
121-
// contains unbound type parameters. It could be a slight
122-
// optimization to stop iterating early.
123-
let errors = fulfill_cx.select_all_or_error(infcx);
124-
if !errors.is_empty() {
125-
infcx.tcx.sess.delay_span_bug(
126-
rustc_span::DUMMY_SP,
127-
&format!(
128-
"Encountered errors `{:?}` resolving bounds outside of type inference",
129-
errors
130-
),
131-
);
132-
}
133-
134-
let result = infcx.resolve_vars_if_possible(result);
135-
infcx.tcx.erase_regions(result)
136-
}

compiler/rustc_ty_utils/src/instance.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use rustc_errors::ErrorGuaranteed;
22
use rustc_hir::def_id::{DefId, LocalDefId};
33
use rustc_infer::infer::TyCtxtInferExt;
4+
use rustc_middle::traits::CodegenObligationError;
45
use rustc_middle::ty::subst::SubstsRef;
56
use rustc_middle::ty::{self, Binder, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitor};
67
use rustc_span::{sym, DUMMY_SP};
@@ -212,7 +213,22 @@ fn resolve_associated_item<'tcx>(
212213
let mut bound_vars_collector = BoundVarsCollector::new();
213214
trait_ref.visit_with(&mut bound_vars_collector);
214215
let trait_binder = ty::Binder::bind_with_vars(trait_ref, bound_vars_collector.into_vars(tcx));
215-
let vtbl = tcx.codegen_fulfill_obligation((param_env, trait_binder))?;
216+
let vtbl = match tcx.codegen_fulfill_obligation((param_env, trait_binder)) {
217+
Ok(vtbl) => vtbl,
218+
Err(CodegenObligationError::Ambiguity) => {
219+
let reported = tcx.sess.delay_span_bug(
220+
tcx.def_span(trait_item_id),
221+
&format!(
222+
"encountered ambiguity selecting `{:?}` during codegen, presuming due to \
223+
overflow or prior type error",
224+
trait_binder
225+
),
226+
);
227+
return Err(reported);
228+
}
229+
Err(CodegenObligationError::Unimplemented) => return Ok(None),
230+
Err(CodegenObligationError::FulfillmentError) => return Ok(None),
231+
};
216232

217233
// Now that we know which impl is being used, we can dispatch to
218234
// the actual function:

src/test/ui/const-generics/generic_const_exprs/issue-85848.rs

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ fn writes_to_path<C>(cap: &C) {
2424
writes_to_specific_path(&cap);
2525
//~^ ERROR: the trait bound `(): _Contains<&C>` is not satisfied [E0277]
2626
//~| ERROR: unconstrained generic constant
27+
//~| ERROR: mismatched types [E0308]
2728
}
2829

2930
fn writes_to_specific_path<C: Delegates<()>>(cap: &C) {}

src/test/ui/const-generics/generic_const_exprs/issue-85848.stderr

+14-4
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ note: required because of the requirements on the impl of `Delegates<()>` for `&
1818
LL | impl<T, U> Delegates<U> for T where T: Contains<U, true> {}
1919
| ^^^^^^^^^^^^ ^
2020
note: required by a bound in `writes_to_specific_path`
21-
--> $DIR/issue-85848.rs:29:31
21+
--> $DIR/issue-85848.rs:30:31
2222
|
2323
LL | fn writes_to_specific_path<C: Delegates<()>>(cap: &C) {}
2424
| ^^^^^^^^^^^^^ required by this bound in `writes_to_specific_path`
@@ -43,11 +43,21 @@ note: required because of the requirements on the impl of `Delegates<()>` for `&
4343
LL | impl<T, U> Delegates<U> for T where T: Contains<U, true> {}
4444
| ^^^^^^^^^^^^ ^
4545
note: required by a bound in `writes_to_specific_path`
46-
--> $DIR/issue-85848.rs:29:31
46+
--> $DIR/issue-85848.rs:30:31
4747
|
4848
LL | fn writes_to_specific_path<C: Delegates<()>>(cap: &C) {}
4949
| ^^^^^^^^^^^^^ required by this bound in `writes_to_specific_path`
5050

51-
error: aborting due to 2 previous errors
51+
error[E0308]: mismatched types
52+
--> $DIR/issue-85848.rs:24:5
53+
|
54+
LL | writes_to_specific_path(&cap);
55+
| ^^^^^^^^^^^^^^^^^^^^^^^ expected `true`, found `{ contains::<T, U>() }`
56+
|
57+
= note: expected type `true`
58+
found type `{ contains::<T, U>() }`
59+
60+
error: aborting due to 3 previous errors
5261

53-
For more information about this error, try `rustc --explain E0277`.
62+
Some errors have detailed explanations: E0277, E0308.
63+
For more information about an error, try `rustc --explain E0277`.

src/test/ui/const-generics/issues/issue-86530.rs

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ where
1515
fn unit_literals() {
1616
z(" ");
1717
//~^ ERROR: the trait bound `&str: X` is not satisfied
18+
//~| ERROR: unconstrained generic constant
1819
}
1920

2021
fn main() {}

src/test/ui/const-generics/issues/issue-86530.stderr

+17-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,22 @@ LL | where
1515
LL | T: X,
1616
| ^ required by this bound in `z`
1717

18-
error: aborting due to previous error
18+
error: unconstrained generic constant
19+
--> $DIR/issue-86530.rs:16:5
20+
|
21+
LL | z(" ");
22+
| ^
23+
|
24+
= help: try adding a `where` bound using this expression: `where [(); T::Y]:`
25+
note: required by a bound in `z`
26+
--> $DIR/issue-86530.rs:11:10
27+
|
28+
LL | fn z<T>(t: T)
29+
| - required by a bound in this
30+
...
31+
LL | [(); T::Y]: ,
32+
| ^^^^ required by this bound in `z`
33+
34+
error: aborting due to 2 previous errors
1935

2036
For more information about this error, try `rustc --explain E0277`.

src/test/ui/issues/issue-77919.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
fn main() {
22
[1; <Multiply<Five, Five>>::VAL];
3+
//~^ ERROR: constant expression depends on a generic parameter
34
}
45
trait TypeVal<T> {
56
const VAL: T;

src/test/ui/issues/issue-77919.stderr

+12-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0412]: cannot find type `PhantomData` in this scope
2-
--> $DIR/issue-77919.rs:9:9
2+
--> $DIR/issue-77919.rs:10:9
33
|
44
LL | _n: PhantomData,
55
| ^^^^^^^^^^^ not found in this scope
@@ -10,23 +10,31 @@ LL | use std::marker::PhantomData;
1010
|
1111

1212
error[E0412]: cannot find type `VAL` in this scope
13-
--> $DIR/issue-77919.rs:11:63
13+
--> $DIR/issue-77919.rs:12:63
1414
|
1515
LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
1616
| - ^^^ not found in this scope
1717
| |
1818
| help: you might be missing a type parameter: `, VAL`
1919

2020
error[E0046]: not all trait items implemented, missing: `VAL`
21-
--> $DIR/issue-77919.rs:11:1
21+
--> $DIR/issue-77919.rs:12:1
2222
|
2323
LL | const VAL: T;
2424
| ------------- `VAL` from trait
2525
...
2626
LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
2727
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation
2828

29-
error: aborting due to 3 previous errors
29+
error: constant expression depends on a generic parameter
30+
--> $DIR/issue-77919.rs:2:9
31+
|
32+
LL | [1; <Multiply<Five, Five>>::VAL];
33+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
34+
|
35+
= note: this may fail depending on what value the parameter takes
36+
37+
error: aborting due to 4 previous errors
3038

3139
Some errors have detailed explanations: E0046, E0412.
3240
For more information about an error, try `rustc --explain E0046`.

src/test/ui/recursion/issue-83150.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// build-fail
2-
//~^ overflow evaluating
2+
//~^ ERROR overflow evaluating the requirement
33

44
fn main() {
55
let mut iter = 0u8..1;

0 commit comments

Comments
 (0)