Skip to content

Commit 734209e

Browse files
Normalize assoc types when checking ret ty of main
This fixes #88609. Previously, the return type of `fn main()` would not have any associated type projections within normalized before checking if it implements the standard library trait `std::process::Termination`. This commit appears to fix it. This feels vaguely symptomatic of a problem in the underlying trait solving engine, but I am not sure how I would solve that. I am unsure why the example in #88609 with `assert_impl_termination` and `fn foo()` work, but simply `fn main()` doesn't. The way that I solved this is also probably not the best way to do this, so please let me know if there is a better way to do this. I have added a build-pass regression test for this issue.
1 parent 8ceea01 commit 734209e

File tree

2 files changed

+36
-1
lines changed

2 files changed

+36
-1
lines changed

compiler/rustc_typeck/src/lib.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ use rustc_middle::util;
109109
use rustc_session::config::EntryFnType;
110110
use rustc_span::{symbol::sym, Span, DUMMY_SP};
111111
use rustc_target::spec::abi::Abi;
112+
use rustc_trait_selection::infer::InferCtxtExt;
112113
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
113114
use rustc_trait_selection::traits::{
114115
self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _,
@@ -328,7 +329,22 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
328329
ObligationCauseCode::MainFunctionType,
329330
);
330331
let mut fulfillment_cx = traits::FulfillmentContext::new();
331-
fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), return_ty, term_id, cause);
332+
// normalize any potential projections in the return type, then add
333+
// any possible obligations to the fulfillment context.
334+
// HACK(ThePuzzlemaker) this feels symptomatic of a problem within
335+
// checking trait fulfillment, not this here. I'm not sure why it
336+
// works in the example in `fn test()` given in #88609? This also
337+
// probably isn't the best way to do this.
338+
let normalized = infcx.partially_normalize_associated_types_in(
339+
cause.clone(),
340+
ty::ParamEnv::empty(),
341+
return_ty,
342+
);
343+
let new_ty = normalized.value;
344+
for obligation in normalized.obligations {
345+
fulfillment_cx.register_predicate_obligation(&infcx, obligation);
346+
}
347+
fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), new_ty, term_id, cause);
332348
if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
333349
infcx.report_fulfillment_errors(&err, None, false);
334350
error = true;

src/test/ui/typeck/issue-88609.rs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Regression test for #88609:
2+
// The return type for `main` is not normalized while checking if it implements
3+
// the trait `std::process::Termination`.
4+
5+
// build-pass
6+
7+
trait Same {
8+
type Output;
9+
}
10+
11+
impl<T> Same for T {
12+
type Output = T;
13+
}
14+
15+
type Unit = <() as Same>::Output;
16+
17+
fn main() -> Result<Unit, std::io::Error> {
18+
unimplemented!()
19+
}

0 commit comments

Comments
 (0)