diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index aa8094a60dd08..715f5be8e2f4b 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -14,6 +14,7 @@ use rustc_infer::traits::Normalized; use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor}; +use rustc_span::DUMMY_SP; use std::ops::ControlFlow; @@ -253,7 +254,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { let result = tcx.normalize_projection_ty(c_data)?; // We don't expect ambiguity. if result.is_ambiguous() { - bug!("unexpected ambiguity: {:?} {:?}", c_data, result); + // Rustdoc normalizes possibly not well-formed types, so only + // treat this as a bug if we're not in rustdoc. + if !tcx.sess.opts.actually_rustdoc { + tcx.sess.delay_span_bug( + DUMMY_SP, + format!("unexpected ambiguity: {:?} {:?}", c_data, result), + ); + } + return Err(NoSolution); } let InferOk { value: result, obligations } = self.infcx.instantiate_query_response_and_region_obligations( @@ -296,7 +305,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { let result = tcx.normalize_projection_ty(c_data)?; // We don't expect ambiguity. if result.is_ambiguous() { - bug!("unexpected ambiguity: {:?} {:?}", c_data, result); + // Rustdoc normalizes possibly not well-formed types, so only + // treat this as a bug if we're not in rustdoc. + if !tcx.sess.opts.actually_rustdoc { + tcx.sess.delay_span_bug( + DUMMY_SP, + format!("unexpected ambiguity: {:?} {:?}", c_data, result), + ); + } + return Err(NoSolution); } let InferOk { value: result, obligations } = self.infcx.instantiate_query_response_and_region_obligations( diff --git a/src/test/rustdoc/not-wf-ambiguous-normalization.rs b/src/test/rustdoc/not-wf-ambiguous-normalization.rs new file mode 100644 index 0000000000000..1e9f925f8458d --- /dev/null +++ b/src/test/rustdoc/not-wf-ambiguous-normalization.rs @@ -0,0 +1,24 @@ +// compile-flags: -Znormalize-docs + +#![feature(type_alias_impl_trait)] + +trait Allocator { + type Buffer; +} + +struct DefaultAllocator; + +// This unconstrained impl parameter causes the normalization of +// `::Buffer` to be ambiguous, +// which caused an ICE with `-Znormalize-docs`. +impl Allocator for DefaultAllocator { + type Buffer = (); +} + +type A = impl Fn(::Buffer); + +fn foo() -> A { + |_| () +} + +fn main() {} diff --git a/src/test/ui/impl-trait/issue-103181-1.rs b/src/test/ui/impl-trait/issue-103181-1.rs new file mode 100644 index 0000000000000..197aedf9d98bc --- /dev/null +++ b/src/test/ui/impl-trait/issue-103181-1.rs @@ -0,0 +1,85 @@ +// edition:2021 + +mod hyper { + use std::{fmt::Debug, future::Future, marker::PhantomData, pin::Pin, task::Poll}; + + pub trait HttpBody { + type Error; + } + impl HttpBody for () { + //~^ ERROR not all trait items implemented, missing: `Error` + // don't implement `Error` here for the ICE + } + + pub struct Server(I, S); + + pub fn serve(_: S) -> Server { + todo!() + } + + impl Future for Server<(), S> + where + S: MakeServiceRef<(), (), ResBody = B>, + B: HttpBody, + B::Error: Debug, + { + type Output = (); + + fn poll(self: Pin<&mut Self>, _: &mut std::task::Context<'_>) -> Poll { + todo!() + } + } + + pub trait MakeServiceRef { + type ResBody; + } + + impl MakeServiceRef<(), ()> for T + where + T: for<'a> Service<&'a (), Response = S>, + S: Service<()>, + { + type ResBody = (); + } + + pub struct MakeServiceFn(pub F); + pub struct ServiceFn(pub PhantomData<(F, R)>); + + pub trait Service { + type Response; + } + + impl<'t, F, Ret, Target, Svc> Service<&'t Target> for MakeServiceFn + where + F: Fn() -> Ret, + Ret: Future>, + { + type Response = Svc; + } + + impl Service for ServiceFn + where + F: Fn() -> Ret, + Ret: Future>, + { + type Response = ResBody; + } +} + +async fn smarvice() -> Result<(), ()> { + Ok(()) +} + +fn service_fn(f: F) -> hyper::ServiceFn +where + F: Fn() -> S, +{ + hyper::ServiceFn(std::marker::PhantomData) +} + +async fn iceice() { + let service = hyper::MakeServiceFn(|| async { Ok::<_, ()>(service_fn(|| smarvice())) }); + hyper::serve::<(), _>(service).await; +} + +fn main() {} diff --git a/src/test/ui/impl-trait/issue-103181-1.stderr b/src/test/ui/impl-trait/issue-103181-1.stderr new file mode 100644 index 0000000000000..cd026607d52fc --- /dev/null +++ b/src/test/ui/impl-trait/issue-103181-1.stderr @@ -0,0 +1,12 @@ +error[E0046]: not all trait items implemented, missing: `Error` + --> $DIR/issue-103181-1.rs:9:5 + | +LL | type Error; + | ---------- `Error` from trait +LL | } +LL | impl HttpBody for () { + | ^^^^^^^^^^^^^^^^^^^^ missing `Error` in implementation + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0046`. diff --git a/src/test/ui/impl-trait/issue-103181-2.rs b/src/test/ui/impl-trait/issue-103181-2.rs new file mode 100644 index 0000000000000..b43ac45075e2b --- /dev/null +++ b/src/test/ui/impl-trait/issue-103181-2.rs @@ -0,0 +1,29 @@ +// edition:2021 + +trait SendFuture: Send { + type Output; +} + +impl SendFuture for Fut { + type Output = (); +} + +async fn broken_fut() { + ident_error; + //~^ ERROR cannot find value `ident_error` in this scope +} + +// triggers normalization of `::Output`, +// which requires `Fut: Send`. +fn normalize(_: Fut, _: Fut::Output) {} + +async fn iceice() +// <- async fn is necessary +where + A: Send, + B: Send, // <- a second bound +{ + normalize(broken_fut(), ()); +} + +fn main() {} diff --git a/src/test/ui/impl-trait/issue-103181-2.stderr b/src/test/ui/impl-trait/issue-103181-2.stderr new file mode 100644 index 0000000000000..5eb2dd9184bec --- /dev/null +++ b/src/test/ui/impl-trait/issue-103181-2.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `ident_error` in this scope + --> $DIR/issue-103181-2.rs:12:5 + | +LL | ident_error; + | ^^^^^^^^^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`.