Skip to content
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

Remove save_and_restore_in_snapshot_flag, use ObligationCtxt more #104206

Merged
merged 3 commits into from
Nov 12, 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
33 changes: 7 additions & 26 deletions compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryRespons
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
use rustc_infer::infer::{InferOk, InferResult};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{
Expand All @@ -32,9 +33,7 @@ use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::{
self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt,
};
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, ObligationCtxt};

use std::collections::hash_map::Entry;
use std::slice;
Expand Down Expand Up @@ -766,34 +765,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

let expect_args = self
.fudge_inference_if_ok(|| {
let ocx = ObligationCtxt::new_in_snapshot(self);

// Attempt to apply a subtyping relationship between the formal
// return type (likely containing type variables if the function
// is polymorphic) and the expected return type.
// No argument expectations are produced if unification fails.
let origin = self.misc(call_span);
let ures = self.at(&origin, self.param_env).sup(ret_ty, formal_ret);

// FIXME(#27336) can't use ? here, Try::from_error doesn't default
// to identity so the resulting type is not constrained.
match ures {
Ok(ok) => {
// Process any obligations locally as much as
// we can. We don't care if some things turn
// out unconstrained or ambiguous, as we're
// just trying to get hints here.
let errors = self.save_and_restore_in_snapshot_flag(|_| {
let mut fulfill = <dyn TraitEngine<'_>>::new(self.tcx);
for obligation in ok.obligations {
fulfill.register_predicate_obligation(self, obligation);
}
fulfill.select_where_possible(self)
});

if !errors.is_empty() {
return Err(());
}
}
Err(_) => return Err(()),
ocx.sup(&origin, self.param_env, ret_ty, formal_ret)?;
if !ocx.select_where_possible().is_empty() {
return Err(TypeError::Mismatch);
}

// Record all the argument types, with the substitutions
Expand Down
26 changes: 0 additions & 26 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -778,32 +778,6 @@ impl<'tcx> InferCtxt<'tcx> {
}
}

/// Clear the "currently in a snapshot" flag, invoke the closure,
/// then restore the flag to its original value. This flag is a
/// debugging measure designed to detect cases where we start a
/// snapshot, create type variables, and register obligations
/// which may involve those type variables in the fulfillment cx,
/// potentially leaving "dangling type variables" behind.
/// In such cases, an assertion will fail when attempting to
/// register obligations, within a snapshot. Very useful, much
/// better than grovelling through megabytes of `RUSTC_LOG` output.
///
/// HOWEVER, in some cases the flag is unhelpful. In particular, we
/// sometimes create a "mini-fulfilment-cx" in which we enroll
/// obligations. As long as this fulfillment cx is fully drained
/// before we return, this is not a problem, as there won't be any
/// escaping obligations in the main cx. In those cases, you can
/// use this function.
pub fn save_and_restore_in_snapshot_flag<F, R>(&self, func: F) -> R
where
F: FnOnce(&Self) -> R,
{
let flag = self.in_snapshot.replace(false);
let result = func(self);
self.in_snapshot.set(flag);
result
}

fn start_snapshot(&self) -> CombinedSnapshot<'tcx> {
debug!("start_snapshot()");

Expand Down
50 changes: 24 additions & 26 deletions compiler/rustc_trait_selection/src/traits/specialize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html

pub mod specialization_graph;
use rustc_infer::traits::{TraitEngine, TraitEngineExt as _};
use specialization_graph::GraphExt;

use crate::errors::NegativePositiveConflict;
use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt};
use crate::traits::engine::TraitEngineExt as _;
use crate::traits::select::IntercrateAmbiguityCause;
use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause};
use rustc_data_structures::fx::FxIndexSet;
Expand Down Expand Up @@ -200,36 +202,32 @@ fn fulfill_implication<'tcx>(
return Err(());
};

// Needs to be `in_snapshot` because this function is used to rebase
// substitutions, which may happen inside of a select within a probe.
let mut engine = <dyn TraitEngine<'tcx>>::new_in_snapshot(infcx.tcx);
// attempt to prove all of the predicates for impl2 given those for impl1
// (which are packed up in penv)
engine.register_predicate_obligations(infcx, obligations.chain(more_obligations));

infcx.save_and_restore_in_snapshot_flag(|infcx| {
let errors = traits::fully_solve_obligations(&infcx, obligations.chain(more_obligations));
match &errors[..] {
[] => {
debug!(
"fulfill_implication: an impl for {:?} specializes {:?}",
source_trait, target_trait
);
let errors = engine.select_all_or_error(infcx);
if !errors.is_empty() {
// no dice!
debug!(
"fulfill_implication: for impls on {:?} and {:?}, \
could not fulfill: {:?} given {:?}",
source_trait,
target_trait,
errors,
param_env.caller_bounds()
);
return Err(());
}

// Now resolve the *substitution* we built for the target earlier, replacing
// the inference variables inside with whatever we got from fulfillment.
Ok(infcx.resolve_vars_if_possible(target_substs))
}
errors => {
// no dice!
debug!(
"fulfill_implication: for impls on {:?} and {:?}, \
could not fulfill: {:?} given {:?}",
source_trait,
target_trait,
errors,
param_env.caller_bounds()
);
Err(())
}
}
})
debug!("fulfill_implication: an impl for {:?} specializes {:?}", source_trait, target_trait);

// Now resolve the *substitution* we built for the target earlier, replacing
// the inference variables inside with whatever we got from fulfillment.
Ok(infcx.resolve_vars_if_possible(target_substs))
}

// Query provider for `specialization_graph_of`.
Expand Down
Loading