mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 23:04:33 +00:00
Auto merge of #102254 - matthiaskrgr:rollup-gitu6li, r=matthiaskrgr
Rollup of 5 pull requests Successful merges: - #102016 (implied_bounds: deal with inference vars) - #102161 (Resolve async fn signature even without body (e.g., in trait)) - #102216 (rustdoc: Stabilize --diagnostic-width) - #102240 (rustdoc: remove unused CSS `#main-content > .line-numbers`) - #102242 (rustdoc: remove unused CSS `.summary`) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
6f6010b08b
@ -53,6 +53,7 @@ pub struct OutlivesEnvironment<'tcx> {
|
||||
}
|
||||
|
||||
/// Builder of OutlivesEnvironment.
|
||||
#[derive(Debug)]
|
||||
struct OutlivesEnvironmentBuilder<'tcx> {
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
region_relation: TransitiveRelationBuilder<Region<'tcx>>,
|
||||
@ -109,6 +110,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
|
||||
|
||||
impl<'a, 'tcx> OutlivesEnvironmentBuilder<'tcx> {
|
||||
#[inline]
|
||||
#[instrument(level = "debug")]
|
||||
fn build(self) -> OutlivesEnvironment<'tcx> {
|
||||
OutlivesEnvironment {
|
||||
param_env: self.param_env,
|
||||
|
@ -805,7 +805,12 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||
sig.decl.has_self(),
|
||||
sig.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)),
|
||||
&sig.decl.output,
|
||||
)
|
||||
);
|
||||
|
||||
this.record_lifetime_params_for_async(
|
||||
fn_id,
|
||||
sig.header.asyncness.opt_return_id(),
|
||||
);
|
||||
},
|
||||
);
|
||||
return;
|
||||
@ -847,41 +852,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||
},
|
||||
);
|
||||
|
||||
// Construct the list of in-scope lifetime parameters for async lowering.
|
||||
// We include all lifetime parameters, either named or "Fresh".
|
||||
// The order of those parameters does not matter, as long as it is
|
||||
// deterministic.
|
||||
if let Some((async_node_id, _)) = async_node_id {
|
||||
let mut extra_lifetime_params = this
|
||||
.r
|
||||
.extra_lifetime_params_map
|
||||
.get(&fn_id)
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
for rib in this.lifetime_ribs.iter().rev() {
|
||||
extra_lifetime_params.extend(
|
||||
rib.bindings
|
||||
.iter()
|
||||
.map(|(&ident, &(node_id, res))| (ident, node_id, res)),
|
||||
);
|
||||
match rib.kind {
|
||||
LifetimeRibKind::Item => break,
|
||||
LifetimeRibKind::AnonymousCreateParameter {
|
||||
binder, ..
|
||||
} => {
|
||||
if let Some(earlier_fresh) =
|
||||
this.r.extra_lifetime_params_map.get(&binder)
|
||||
{
|
||||
extra_lifetime_params.extend(earlier_fresh);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
this.r
|
||||
.extra_lifetime_params_map
|
||||
.insert(async_node_id, extra_lifetime_params);
|
||||
}
|
||||
this.record_lifetime_params_for_async(fn_id, async_node_id);
|
||||
|
||||
if let Some(body) = body {
|
||||
// Ignore errors in function bodies if this is rustdoc
|
||||
@ -3926,6 +3897,36 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
Some((ident.name, ns)),
|
||||
)
|
||||
}
|
||||
|
||||
/// Construct the list of in-scope lifetime parameters for async lowering.
|
||||
/// We include all lifetime parameters, either named or "Fresh".
|
||||
/// The order of those parameters does not matter, as long as it is
|
||||
/// deterministic.
|
||||
fn record_lifetime_params_for_async(
|
||||
&mut self,
|
||||
fn_id: NodeId,
|
||||
async_node_id: Option<(NodeId, Span)>,
|
||||
) {
|
||||
if let Some((async_node_id, _)) = async_node_id {
|
||||
let mut extra_lifetime_params =
|
||||
self.r.extra_lifetime_params_map.get(&fn_id).cloned().unwrap_or_default();
|
||||
for rib in self.lifetime_ribs.iter().rev() {
|
||||
extra_lifetime_params.extend(
|
||||
rib.bindings.iter().map(|(&ident, &(node_id, res))| (ident, node_id, res)),
|
||||
);
|
||||
match rib.kind {
|
||||
LifetimeRibKind::Item => break,
|
||||
LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
|
||||
if let Some(earlier_fresh) = self.r.extra_lifetime_params_map.get(&binder) {
|
||||
extra_lifetime_params.extend(earlier_fresh);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
self.r.extra_lifetime_params_map.insert(async_node_id, extra_lifetime_params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct LifetimeCountVisitor<'a, 'b> {
|
||||
|
@ -46,7 +46,7 @@ impl<'a, 'cx, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'cx, 'tcx> {
|
||||
/// Note that this may cause outlives obligations to be injected
|
||||
/// into the inference context with this body-id.
|
||||
/// - `ty`, the type that we are supposed to assume is WF.
|
||||
#[instrument(level = "debug", skip(self, param_env, body_id))]
|
||||
#[instrument(level = "debug", skip(self, param_env, body_id), ret)]
|
||||
fn implied_outlives_bounds(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
@ -71,6 +71,7 @@ impl<'a, 'cx, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'cx, 'tcx> {
|
||||
let TypeOpOutput { output, constraints, .. } = result;
|
||||
|
||||
if let Some(constraints) = constraints {
|
||||
debug!(?constraints);
|
||||
// Instantiation may have produced new inference variables and constraints on those
|
||||
// variables. Process these constraints.
|
||||
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(self.tcx);
|
||||
|
@ -49,7 +49,8 @@ fn compute_implied_outlives_bounds<'tcx>(
|
||||
let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default();
|
||||
let mut wf_args = vec![ty.into()];
|
||||
|
||||
let mut implied_bounds = vec![];
|
||||
let mut outlives_bounds: Vec<ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>> =
|
||||
vec![];
|
||||
|
||||
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx);
|
||||
|
||||
@ -65,30 +66,17 @@ fn compute_implied_outlives_bounds<'tcx>(
|
||||
// than the ultimate set. (Note: normally there won't be
|
||||
// unresolved inference variables here anyway, but there might be
|
||||
// during typeck under some circumstances.)
|
||||
//
|
||||
// FIXME(@lcnr): It's not really "always fine", having fewer implied
|
||||
// bounds can be backward incompatible, e.g. #101951 was caused by
|
||||
// us not dealing with inference vars in `TypeOutlives` predicates.
|
||||
let obligations = wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, 0, arg, DUMMY_SP)
|
||||
.unwrap_or_default();
|
||||
|
||||
// N.B., all of these predicates *ought* to be easily proven
|
||||
// true. In fact, their correctness is (mostly) implied by
|
||||
// other parts of the program. However, in #42552, we had
|
||||
// an annoying scenario where:
|
||||
//
|
||||
// - Some `T::Foo` gets normalized, resulting in a
|
||||
// variable `_1` and a `T: Trait<Foo=_1>` constraint
|
||||
// (not sure why it couldn't immediately get
|
||||
// solved). This result of `_1` got cached.
|
||||
// - These obligations were dropped on the floor here,
|
||||
// rather than being registered.
|
||||
// - Then later we would get a request to normalize
|
||||
// `T::Foo` which would result in `_1` being used from
|
||||
// the cache, but hence without the `T: Trait<Foo=_1>`
|
||||
// constraint. As a result, `_1` never gets resolved,
|
||||
// and we get an ICE (in dropck).
|
||||
//
|
||||
// Therefore, we register any predicates involving
|
||||
// inference variables. We restrict ourselves to those
|
||||
// involving inference variables both for efficiency and
|
||||
// to avoids duplicate errors that otherwise show up.
|
||||
// While these predicates should all be implied by other parts of
|
||||
// the program, they are still relevant as they may constrain
|
||||
// inference variables, which is necessary to add the correct
|
||||
// implied bounds in some cases, mostly when dealing with projections.
|
||||
fulfill_cx.register_predicate_obligations(
|
||||
infcx,
|
||||
obligations.iter().filter(|o| o.predicate.has_infer_types_or_consts()).cloned(),
|
||||
@ -96,10 +84,10 @@ fn compute_implied_outlives_bounds<'tcx>(
|
||||
|
||||
// From the full set of obligations, just filter down to the
|
||||
// region relationships.
|
||||
implied_bounds.extend(obligations.into_iter().flat_map(|obligation| {
|
||||
outlives_bounds.extend(obligations.into_iter().filter_map(|obligation| {
|
||||
assert!(!obligation.has_escaping_bound_vars());
|
||||
match obligation.predicate.kind().no_bound_vars() {
|
||||
None => vec![],
|
||||
None => None,
|
||||
Some(pred) => match pred {
|
||||
ty::PredicateKind::Trait(..)
|
||||
| ty::PredicateKind::Subtype(..)
|
||||
@ -109,21 +97,18 @@ fn compute_implied_outlives_bounds<'tcx>(
|
||||
| ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => vec![],
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
|
||||
ty::PredicateKind::WellFormed(arg) => {
|
||||
wf_args.push(arg);
|
||||
vec![]
|
||||
None
|
||||
}
|
||||
|
||||
ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
|
||||
vec![OutlivesBound::RegionSubRegion(r_b, r_a)]
|
||||
Some(ty::OutlivesPredicate(r_a.into(), r_b))
|
||||
}
|
||||
|
||||
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, r_b)) => {
|
||||
let ty_a = infcx.resolve_vars_if_possible(ty_a);
|
||||
let mut components = smallvec![];
|
||||
push_outlives_components(tcx, ty_a, &mut components);
|
||||
implied_bounds_from_components(r_b, components)
|
||||
Some(ty::OutlivesPredicate(ty_a.into(), r_b))
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -133,9 +118,27 @@ fn compute_implied_outlives_bounds<'tcx>(
|
||||
// Ensure that those obligations that we had to solve
|
||||
// get solved *here*.
|
||||
match fulfill_cx.select_all_or_error(infcx).as_slice() {
|
||||
[] => Ok(implied_bounds),
|
||||
_ => Err(NoSolution),
|
||||
[] => (),
|
||||
_ => return Err(NoSolution),
|
||||
}
|
||||
|
||||
// We lazily compute the outlives components as
|
||||
// `select_all_or_error` constrains inference variables.
|
||||
let implied_bounds = outlives_bounds
|
||||
.into_iter()
|
||||
.flat_map(|ty::OutlivesPredicate(a, r_b)| match a.unpack() {
|
||||
ty::GenericArgKind::Lifetime(r_a) => vec![OutlivesBound::RegionSubRegion(r_b, r_a)],
|
||||
ty::GenericArgKind::Type(ty_a) => {
|
||||
let ty_a = infcx.resolve_vars_if_possible(ty_a);
|
||||
let mut components = smallvec![];
|
||||
push_outlives_components(tcx, ty_a, &mut components);
|
||||
implied_bounds_from_components(r_b, components)
|
||||
}
|
||||
ty::GenericArgKind::Const(_) => unreachable!(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(implied_bounds)
|
||||
}
|
||||
|
||||
/// When we have an implied bound that `T: 'a`, we can further break
|
||||
|
@ -140,6 +140,7 @@ pub(crate) fn compare_impl_method<'tcx>(
|
||||
///
|
||||
/// Finally we register each of these predicates as an obligation and check that
|
||||
/// they hold.
|
||||
#[instrument(level = "debug", skip(tcx, impl_m_span, impl_trait_ref))]
|
||||
fn compare_predicate_entailment<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
impl_m: &AssocItem,
|
||||
|
@ -1130,10 +1130,6 @@ so that we can apply CSS-filters to change the arrow color in themes */
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.summary {
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
pre.rust .question-mark {
|
||||
font-weight: bold;
|
||||
}
|
||||
@ -1917,10 +1913,6 @@ in storage.js plus the media query with (min-width: 701px)
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
|
||||
#main-content > .line-numbers {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.notable-traits .notable-traits-tooltiptext {
|
||||
left: 0;
|
||||
top: 100%;
|
||||
|
@ -461,7 +461,7 @@ fn opts() -> Vec<RustcOptGroup> {
|
||||
"human|json|short",
|
||||
)
|
||||
}),
|
||||
unstable("diagnostic-width", |o| {
|
||||
stable("diagnostic-width", |o| {
|
||||
o.optopt(
|
||||
"",
|
||||
"diagnostic-width",
|
||||
|
@ -1,4 +1,4 @@
|
||||
// compile-flags: -Zunstable-options --diagnostic-width=10
|
||||
// compile-flags: --diagnostic-width=10
|
||||
#![deny(rustdoc::bare_urls)]
|
||||
|
||||
/// This is a long line that contains a http://link.com
|
||||
|
46
src/test/ui/async-await/in-trait/issue-102138.rs
Normal file
46
src/test/ui/async-await/in-trait/issue-102138.rs
Normal file
@ -0,0 +1,46 @@
|
||||
// check-pass
|
||||
// edition:2021
|
||||
|
||||
#![feature(async_fn_in_trait)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
use std::future::Future;
|
||||
|
||||
async fn yield_now() {}
|
||||
|
||||
trait AsyncIterator {
|
||||
type Item;
|
||||
async fn next(&mut self) -> Option<Self::Item>;
|
||||
}
|
||||
|
||||
struct YieldingRange {
|
||||
counter: u32,
|
||||
stop: u32,
|
||||
}
|
||||
|
||||
impl AsyncIterator for YieldingRange {
|
||||
type Item = u32;
|
||||
|
||||
async fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.counter == self.stop {
|
||||
None
|
||||
} else {
|
||||
let c = self.counter;
|
||||
self.counter += 1;
|
||||
yield_now().await;
|
||||
Some(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn async_main() {
|
||||
let mut x = YieldingRange { counter: 0, stop: 10 };
|
||||
|
||||
while let Some(v) = x.next().await {
|
||||
println!("Hi: {v}");
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _ = async_main();
|
||||
}
|
50
src/test/ui/implied-bounds/issue-101951.rs
Normal file
50
src/test/ui/implied-bounds/issue-101951.rs
Normal file
@ -0,0 +1,50 @@
|
||||
// Taken directly from that issue.
|
||||
//
|
||||
// This test detected that we didn't correctly resolve
|
||||
// inference variables when computing implied bounds.
|
||||
//
|
||||
// check-pass
|
||||
pub trait BuilderFn<'a> {
|
||||
type Output;
|
||||
}
|
||||
|
||||
impl<'a, F, Out> BuilderFn<'a> for F
|
||||
where
|
||||
F: FnOnce(&'a mut ()) -> Out,
|
||||
{
|
||||
type Output = Out;
|
||||
}
|
||||
|
||||
pub trait ConstructionFirm {
|
||||
type Builder: for<'a> BuilderFn<'a>;
|
||||
}
|
||||
|
||||
pub trait Campus<T>
|
||||
where
|
||||
T: ConstructionFirm,
|
||||
{
|
||||
fn add_building(
|
||||
&mut self,
|
||||
building: &mut <<T as ConstructionFirm>::Builder as BuilderFn<'_>>::Output,
|
||||
);
|
||||
}
|
||||
|
||||
struct ArchitectsInc {}
|
||||
|
||||
impl ConstructionFirm for ArchitectsInc {
|
||||
type Builder = fn(&mut ()) -> PrettyCondo<'_>;
|
||||
}
|
||||
|
||||
struct PrettyCondo<'a> {
|
||||
_marker: &'a mut (),
|
||||
}
|
||||
|
||||
struct CondoEstate {}
|
||||
|
||||
impl Campus<ArchitectsInc> for CondoEstate {
|
||||
fn add_building(&mut self, _building: &mut PrettyCondo<'_>) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
11
src/test/ui/resolve/name-collision-in-trait-fn-sig.rs
Normal file
11
src/test/ui/resolve/name-collision-in-trait-fn-sig.rs
Normal file
@ -0,0 +1,11 @@
|
||||
// check-pass
|
||||
// This is currently stable behavior, which was almost accidentally made an
|
||||
// error in #102161 since there is no test exercising it. I am not sure if
|
||||
// this _should_ be the desired behavior, but at least we should know if it
|
||||
// changes.
|
||||
|
||||
fn main() {}
|
||||
|
||||
trait Foo {
|
||||
fn fn_with_type_named_same_as_local_in_param(b: i32, b: i32);
|
||||
}
|
Loading…
Reference in New Issue
Block a user