diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2022-10-23 08:14:32 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-10-23 08:14:32 +0200 |
| commit | 72f75d18b15608cfe6461892f3ed53cdcdf248d8 (patch) | |
| tree | 88fa6cd940d91186b3ac91c1cbf5d04712d94718 | |
| parent | ff689a1404081871afd31814f31db508bcd560dc (diff) | |
| parent | cb61113cdc158de18993a94bc6bb39aee6950a9b (diff) | |
| download | rust-72f75d18b15608cfe6461892f3ed53cdcdf248d8.tar.gz rust-72f75d18b15608cfe6461892f3ed53cdcdf248d8.zip | |
Rollup merge of #103368 - compiler-errors:normalization-ambiguity-bug, r=oli-obk
Delay ambiguity span bug in normalize query iff not rustdoc Oli and I decided that the compiler debt of adding another usage of `tcx.sess.opts.actually_rustdoc` is fine, because we don't really want to add more complexity to the normalize query, and moving rustdoc to use fulfill normalization (`fully_normalize`, i.e. not use the normalize query) is unnecessary overhead given that it's skipping binders and stuff. r? oli-obk Fixes #102827 Fixes #103181
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/query/normalize.rs | 21 | ||||
| -rw-r--r-- | src/test/rustdoc/not-wf-ambiguous-normalization.rs | 24 | ||||
| -rw-r--r-- | src/test/ui/impl-trait/issue-103181-1.rs | 85 | ||||
| -rw-r--r-- | src/test/ui/impl-trait/issue-103181-1.stderr | 12 | ||||
| -rw-r--r-- | src/test/ui/impl-trait/issue-103181-2.rs | 29 | ||||
| -rw-r--r-- | src/test/ui/impl-trait/issue-103181-2.stderr | 9 |
6 files changed, 178 insertions, 2 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index aa8094a60dd..715f5be8e2f 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 00000000000..1e9f925f845 --- /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 +// `<DefaultAllocator as Allocator>::Buffer` to be ambiguous, +// which caused an ICE with `-Znormalize-docs`. +impl<T> Allocator for DefaultAllocator { + type Buffer = (); +} + +type A = impl Fn(<DefaultAllocator as Allocator>::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 00000000000..197aedf9d98 --- /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>(I, S); + + pub fn serve<I, S>(_: S) -> Server<I, S> { + todo!() + } + + impl<S, B> 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<Self::Output> { + todo!() + } + } + + pub trait MakeServiceRef<Target, ReqBody> { + type ResBody; + } + + impl<T, S> MakeServiceRef<(), ()> for T + where + T: for<'a> Service<&'a (), Response = S>, + S: Service<()>, + { + type ResBody = (); + } + + pub struct MakeServiceFn<F>(pub F); + pub struct ServiceFn<F, R>(pub PhantomData<(F, R)>); + + pub trait Service<Request> { + type Response; + } + + impl<'t, F, Ret, Target, Svc> Service<&'t Target> for MakeServiceFn<F> + where + F: Fn() -> Ret, + Ret: Future<Output = Result<Svc, ()>>, + { + type Response = Svc; + } + + impl<F, ReqBody, Ret, ResBody, E> Service<ReqBody> for ServiceFn<F, ReqBody> + where + F: Fn() -> Ret, + Ret: Future<Output = Result<ResBody, E>>, + { + type Response = ResBody; + } +} + +async fn smarvice() -> Result<(), ()> { + Ok(()) +} + +fn service_fn<F, R, S>(f: F) -> hyper::ServiceFn<F, R> +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 00000000000..cd026607d52 --- /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 00000000000..b43ac45075e --- /dev/null +++ b/src/test/ui/impl-trait/issue-103181-2.rs @@ -0,0 +1,29 @@ +// edition:2021 + +trait SendFuture: Send { + type Output; +} + +impl<Fut: Send> SendFuture for Fut { + type Output = (); +} + +async fn broken_fut() { + ident_error; + //~^ ERROR cannot find value `ident_error` in this scope +} + +// triggers normalization of `<Fut as SendFuture>::Output`, +// which requires `Fut: Send`. +fn normalize<Fut: SendFuture>(_: Fut, _: Fut::Output) {} + +async fn iceice<A, B>() +// <- 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 00000000000..5eb2dd9184b --- /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`. |
