about summary refs log tree commit diff
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2021-10-05 12:52:41 -0700
committerGitHub <noreply@github.com>2021-10-05 12:52:41 -0700
commit960e49e89b3c09baf9197dc9c87f3ca7755a486c (patch)
tree7ce87a645176134704f0e0d989ea3e5b021357c5
parent25ec8273855fde2d72ae877b397e054de5300e10 (diff)
parent33a28254f21c792cb0bda5427e66efa91b87dd4d (diff)
downloadrust-960e49e89b3c09baf9197dc9c87f3ca7755a486c.tar.gz
rust-960e49e89b3c09baf9197dc9c87f3ca7755a486c.zip
Rollup merge of #88706 - ThePuzzlemaker:issue-88609, r=jackh726
Normalize associated type projections when checking return type 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.
-rw-r--r--compiler/rustc_typeck/src/lib.rs22
-rw-r--r--src/test/ui/typeck/issue-88609.rs19
2 files changed, 40 insertions, 1 deletions
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs
index 8ff074e2fe5..65eedd2daaf 100644
--- a/compiler/rustc_typeck/src/lib.rs
+++ b/compiler/rustc_typeck/src/lib.rs
@@ -107,6 +107,7 @@ use rustc_middle::util;
 use rustc_session::config::EntryFnType;
 use rustc_span::{symbol::sym, Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 use rustc_trait_selection::traits::{
     self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _,
@@ -328,7 +329,26 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
                 ObligationCauseCode::MainFunctionType,
             );
             let mut fulfillment_cx = traits::FulfillmentContext::new();
-            fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), return_ty, term_id, cause);
+            // normalize any potential projections in the return type, then add
+            // any possible obligations to the fulfillment context.
+            // HACK(ThePuzzlemaker) this feels symptomatic of a problem within
+            // checking trait fulfillment, not this here. I'm not sure why it
+            // works in the example in `fn test()` given in #88609? This also
+            // probably isn't the best way to do this.
+            let InferOk { value: norm_return_ty, obligations } = infcx
+                .partially_normalize_associated_types_in(
+                    cause.clone(),
+                    ty::ParamEnv::empty(),
+                    return_ty,
+                );
+            fulfillment_cx.register_predicate_obligations(&infcx, obligations);
+            fulfillment_cx.register_bound(
+                &infcx,
+                ty::ParamEnv::empty(),
+                norm_return_ty,
+                term_id,
+                cause,
+            );
             if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
                 infcx.report_fulfillment_errors(&err, None, false);
                 error = true;
diff --git a/src/test/ui/typeck/issue-88609.rs b/src/test/ui/typeck/issue-88609.rs
new file mode 100644
index 00000000000..dc459c885fa
--- /dev/null
+++ b/src/test/ui/typeck/issue-88609.rs
@@ -0,0 +1,19 @@
+// Regression test for #88609:
+// The return type for `main` is not normalized while checking if it implements
+// the trait `std::process::Termination`.
+
+// build-pass
+
+trait Same {
+    type Output;
+}
+
+impl<T> Same for T {
+    type Output = T;
+}
+
+type Unit = <() as Same>::Output;
+
+fn main() -> Result<Unit, std::io::Error> {
+    unimplemented!()
+}