Skip to content

Commit 960e49e

Browse files
authored
Rollup merge of rust-lang#88706 - ThePuzzlemaker:issue-88609, r=jackh726
Normalize associated type projections when checking return type of main This fixes rust-lang#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 rust-lang#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.
2 parents 25ec827 + 33a2825 commit 960e49e

File tree

2 files changed

+40
-1
lines changed

2 files changed

+40
-1
lines changed

compiler/rustc_typeck/src/lib.rs

+21-1
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ use rustc_middle::util;
107107
use rustc_session::config::EntryFnType;
108108
use rustc_span::{symbol::sym, Span, DUMMY_SP};
109109
use rustc_target::spec::abi::Abi;
110+
use rustc_trait_selection::infer::InferCtxtExt;
110111
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
111112
use rustc_trait_selection::traits::{
112113
self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _,
@@ -328,7 +329,26 @@ 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 InferOk { value: norm_return_ty, obligations } = infcx
339+
.partially_normalize_associated_types_in(
340+
cause.clone(),
341+
ty::ParamEnv::empty(),
342+
return_ty,
343+
);
344+
fulfillment_cx.register_predicate_obligations(&infcx, obligations);
345+
fulfillment_cx.register_bound(
346+
&infcx,
347+
ty::ParamEnv::empty(),
348+
norm_return_ty,
349+
term_id,
350+
cause,
351+
);
332352
if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
333353
infcx.report_fulfillment_errors(&err, None, false);
334354
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)