Skip to content

Rollup of 5 pull requests #102254

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Sep 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compiler/rustc_infer/src/infer/outlives/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>>,
Expand Down Expand Up @@ -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,
Expand Down
73 changes: 37 additions & 36 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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> {
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand All @@ -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);
Expand Down
69 changes: 36 additions & 33 deletions compiler/rustc_traits/src/implied_outlives_bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -65,41 +66,28 @@ 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(),
);

// 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(..)
Expand All @@ -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))
}
},
}
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_typeck/src/check/compare_method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
8 changes: 0 additions & 8 deletions src/librustdoc/html/static/css/rustdoc.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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%;
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ fn opts() -> Vec<RustcOptGroup> {
"human|json|short",
)
}),
unstable("diagnostic-width", |o| {
stable("diagnostic-width", |o| {
o.optopt(
"",
"diagnostic-width",
Expand Down
2 changes: 1 addition & 1 deletion src/test/rustdoc-ui/diagnostic-width.rs
Original file line number Diff line number Diff line change
@@ -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
Expand Down
46 changes: 46 additions & 0 deletions src/test/ui/async-await/in-trait/issue-102138.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 50 additions & 0 deletions src/test/ui/implied-bounds/issue-101951.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 11 additions & 0 deletions src/test/ui/resolve/name-collision-in-trait-fn-sig.rs
Original file line number Diff line number Diff line change
@@ -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);
}