From 2751b867a7fa0b14dbe5ca5f315e8f373bf8a5f3 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 3 Jun 2019 13:46:38 +0100 Subject: [PATCH 1/2] Don't try to lower ReEmpty in NLL --- .../nll/type_check/free_region_relations.rs | 7 +++++++ src/test/ui/nll/empty-type-predicate.rs | 11 +++++++++++ 2 files changed, 18 insertions(+) create mode 100644 src/test/ui/nll/empty-type-predicate.rs diff --git a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs index 3b663ef6dad61..361353f8df4c8 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs @@ -334,6 +334,13 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> { match outlives_bound { OutlivesBound::RegionSubRegion(r1, r2) => { + // `where Type:` is lowered to `where Type: 'empty` so that + // we check `Type` is well formed, but there's no use for + // this bound here. + if let ty::ReEmpty = r1 { + return; + } + // The bound says that `r1 <= r2`; we store `r2: r1`. let r1 = self.universal_regions.to_region_vid(r1); let r2 = self.universal_regions.to_region_vid(r2); diff --git a/src/test/ui/nll/empty-type-predicate.rs b/src/test/ui/nll/empty-type-predicate.rs new file mode 100644 index 0000000000000..75431d40ce542 --- /dev/null +++ b/src/test/ui/nll/empty-type-predicate.rs @@ -0,0 +1,11 @@ +// Regression test for #61315 +// +// `dyn T:` is lowered to `dyn T: ReEmpty` - check that we don't ICE in NLL for +// the unexpected region. + +// compile-pass + +trait T {} +fn f() where dyn T: {} + +fn main() {} From 794239d9a4f9ce0e1a0fb26ee737c80044b76587 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 3 Jun 2019 15:04:40 +0100 Subject: [PATCH 2/2] Don't canonicalize `'static` in normalize --- src/librustc/infer/canonical/canonicalizer.rs | 10 +- src/librustc/traits/query/normalize.rs | 4 +- src/test/ui/nll/issue-61311-normalize.rs | 34 ++++ src/test/ui/nll/issue-61320-normalize.rs | 160 ++++++++++++++++++ 4 files changed, 204 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/nll/issue-61311-normalize.rs create mode 100644 src/test/ui/nll/issue-61320-normalize.rs diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs index 0e9dbcac5cd64..ae4bfcaa90373 100644 --- a/src/librustc/infer/canonical/canonicalizer.rs +++ b/src/librustc/infer/canonical/canonicalizer.rs @@ -115,13 +115,17 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { /// A hacky variant of `canonicalize_query` that does not /// canonicalize `'static`. Unfortunately, the existing leak - /// check treaks `'static` differently in some cases (see also + /// check treats `'static` differently in some cases (see also /// #33684), so if we are performing an operation that may need to /// prove "leak-check" related things, we leave `'static` /// alone. + /// + /// `'static` is also special cased when winnowing candidates when + /// selecting implementation candidates, so we also have to leave `'static` + /// alone for queries that do selection. // - // FIXME(#48536): once we have universes, we can remove this and just use - // `canonicalize_query`. + // FIXME(#48536): once the above issues are resolved, we can remove this + // and just use `canonicalize_query`. pub fn canonicalize_hr_query_hack( &self, value: &V, diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs index d09a9c107869b..0b20ec884fc4d 100644 --- a/src/librustc/traits/query/normalize.rs +++ b/src/librustc/traits/query/normalize.rs @@ -145,7 +145,9 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx let gcx = self.infcx.tcx.global_tcx(); let mut orig_values = OriginalQueryValues::default(); - let c_data = self.infcx.canonicalize_query( + // HACK(matthewjasper) `'static` is special-cased in selection, + // so we cannot canonicalize it. + let c_data = self.infcx.canonicalize_hr_query_hack( &self.param_env.and(*data), &mut orig_values); debug!("QueryNormalizer: c_data = {:#?}", c_data); debug!("QueryNormalizer: orig_values = {:#?}", orig_values); diff --git a/src/test/ui/nll/issue-61311-normalize.rs b/src/test/ui/nll/issue-61311-normalize.rs new file mode 100644 index 0000000000000..1164e9ef2d62f --- /dev/null +++ b/src/test/ui/nll/issue-61311-normalize.rs @@ -0,0 +1,34 @@ +// Regression test for #61311 +// We would ICE after failing to normalize `Self::Proj` in the `impl` below. + +// compile-pass + +pub struct Unit; +trait Obj {} + +trait Bound {} +impl Bound for Unit {} + +pub trait HasProj { + type Proj; +} + +impl HasProj for T { + type Proj = Unit; +} + +trait HasProjFn { + type Proj; + fn the_fn(_: Self::Proj); +} + +impl HasProjFn for Unit +where + Box: HasProj, + as HasProj>::Proj: Bound, +{ + type Proj = Unit; + fn the_fn(_: Self::Proj) {} +} + +fn main() {} diff --git a/src/test/ui/nll/issue-61320-normalize.rs b/src/test/ui/nll/issue-61320-normalize.rs new file mode 100644 index 0000000000000..a36ccd36113b5 --- /dev/null +++ b/src/test/ui/nll/issue-61320-normalize.rs @@ -0,0 +1,160 @@ +// Regression test for #61320 +// This is the same issue as #61311, just a larger test case. + +// compile-pass + +pub struct AndThen +where + A: Future, + B: IntoFuture, +{ + state: (A, B::Future, F), +} + +pub struct FutureResult { + inner: Option>, +} + +impl Future for FutureResult { + type Item = T; + type Error = E; + + fn poll(&mut self) -> Poll { + unimplemented!() + } +} + +pub type Poll = Result; + +impl Future for AndThen +where + A: Future, + B: IntoFuture, + F: FnOnce(A::Item) -> B, +{ + type Item = B::Item; + type Error = B::Error; + + fn poll(&mut self) -> Poll { + unimplemented!() + } +} + +pub trait Future { + type Item; + + type Error; + + fn poll(&mut self) -> Poll; + + fn and_then(self, f: F) -> AndThen + where + F: FnOnce(Self::Item) -> B, + B: IntoFuture, + Self: Sized, + { + unimplemented!() + } +} + +pub trait IntoFuture { + /// The future that this type can be converted into. + type Future: Future; + + /// The item that the future may resolve with. + type Item; + /// The error that the future may resolve with. + type Error; + + /// Consumes this object and produces a future. + fn into_future(self) -> Self::Future; +} + +impl IntoFuture for F { + type Future = F; + type Item = F::Item; + type Error = F::Error; + + fn into_future(self) -> F { + self + } +} + +impl Future for ::std::boxed::Box { + type Item = F::Item; + type Error = F::Error; + + fn poll(&mut self) -> Poll { + (**self).poll() + } +} + +impl IntoFuture for Result { + type Future = FutureResult; + type Item = T; + type Error = E; + + fn into_future(self) -> FutureResult { + unimplemented!() + } +} + +struct Request(T); + +trait RequestContext {} +impl RequestContext for T {} +struct NoContext; +impl AsRef for NoContext { + fn as_ref(&self) -> &Self { + &NoContext + } +} + +type BoxedError = Box; +type DefaultFuture = Box + Send>; + +trait Guard: Sized { + type Result: IntoFuture; + fn from_request(request: &Request<()>) -> Self::Result; +} + +trait FromRequest: Sized { + type Context; + type Future: Future + Send; + fn from_request(request: Request<()>) -> Self::Future; +} + +struct MyGuard; +impl Guard for MyGuard { + type Result = Result; + fn from_request(_request: &Request<()>) -> Self::Result { + Ok(MyGuard) + } +} + +struct Generic { + _inner: I, +} + +impl FromRequest for Generic +where + MyGuard: Guard, + ::Result: IntoFuture, + <::Result as IntoFuture>::Future: Send, + I: FromRequest, +{ + type Future = DefaultFuture; + type Context = NoContext; + fn from_request(headers: Request<()>) -> DefaultFuture { + let _future = ::from_request(&headers) + .into_future() + .and_then(move |_| { + ::from_request(headers) + .into_future() + .and_then(move |fld_inner| Ok(Generic { _inner: fld_inner }).into_future()) + }); + panic!(); + } +} + +fn main() {}