1
Fork 0

Rollup merge of #103488 - oli-obk:impl_trait_for_tait, r=lcnr

Allow opaque types in trait impl headers and rely on coherence to reject unsound cases

r? ````@lcnr````

fixes #99840
This commit is contained in:
Manish Goregaokar 2022-11-22 22:54:38 -05:00 committed by GitHub
commit 53eab246db
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
75 changed files with 545 additions and 313 deletions

View file

@ -841,6 +841,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => {}
ty::PredicateKind::Ambiguous => return false,
};
}
true

View file

@ -18,7 +18,7 @@ use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::Diagnostic;
use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::CRATE_HIR_ID;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::util;
use rustc_middle::traits::specialization_graph::OverlapMode;
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
@ -94,8 +94,9 @@ pub fn overlapping_impls<'tcx>(
return None;
}
let infcx = tcx.infer_ctxt().build();
let selcx = &mut SelectionContext::intercrate(&infcx);
let infcx =
tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).intercrate().build();
let selcx = &mut SelectionContext::new(&infcx);
let overlaps =
overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some();
if !overlaps {
@ -105,8 +106,9 @@ pub fn overlapping_impls<'tcx>(
// In the case where we detect an error, run the check again, but
// this time tracking intercrate ambiguity causes for better
// diagnostics. (These take time and can lead to false errors.)
let infcx = tcx.infer_ctxt().build();
let selcx = &mut SelectionContext::intercrate(&infcx);
let infcx =
tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).intercrate().build();
let selcx = &mut SelectionContext::new(&infcx);
selcx.enable_tracking_intercrate_ambiguity_causes();
Some(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap())
}

View file

@ -1168,6 +1168,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
)
}
ty::PredicateKind::Ambiguous => span_bug!(span, "ambiguous"),
ty::PredicateKind::TypeWellFormedFromEnv(..) => span_bug!(
span,
"TypeWellFormedFromEnv predicate should only exist in the environment"

View file

@ -336,6 +336,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
ty::Binder::dummy(infcx.replace_bound_vars_with_placeholders(binder));
ProcessResult::Changed(mk_pending(vec![obligation.with(infcx.tcx, pred)]))
}
ty::PredicateKind::Ambiguous => ProcessResult::Unchanged,
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("TypeWellFormedFromEnv is only used for Chalk")
}
@ -569,6 +570,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
}
}
}
ty::PredicateKind::Ambiguous => ProcessResult::Unchanged,
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("TypeWellFormedFromEnv is only used for Chalk")
}

View file

@ -319,6 +319,7 @@ fn predicate_references_self<'tcx>(
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::Ambiguous
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
}
}
@ -350,6 +351,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
| ty::PredicateKind::TypeOutlives(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::Ambiguous
| ty::PredicateKind::TypeWellFormedFromEnv(..) => false,
}
})

View file

@ -110,25 +110,6 @@ pub struct SelectionContext<'cx, 'tcx> {
/// require themselves.
freshener: TypeFreshener<'cx, 'tcx>,
/// During coherence we have to assume that other crates may add
/// additional impls which we currently don't know about.
///
/// To deal with this evaluation should be conservative
/// and consider the possibility of impls from outside this crate.
/// This comes up primarily when resolving ambiguity. Imagine
/// there is some trait reference `$0: Bar` where `$0` is an
/// inference variable. If `intercrate` is true, then we can never
/// say for sure that this reference is not implemented, even if
/// there are *no impls at all for `Bar`*, because `$0` could be
/// bound to some type that in a downstream crate that implements
/// `Bar`.
///
/// Outside of coherence we set this to false because we are only
/// interested in types that the user could actually have written.
/// In other words, we consider `$0: Bar` to be unimplemented if
/// there is no type that the user could *actually name* that
/// would satisfy it. This avoids crippling inference, basically.
intercrate: bool,
/// If `intercrate` is set, we remember predicates which were
/// considered ambiguous because of impls potentially added in other crates.
/// This is used in coherence to give improved diagnostics.
@ -226,16 +207,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
SelectionContext {
infcx,
freshener: infcx.freshener_keep_static(),
intercrate: false,
intercrate_ambiguity_causes: None,
query_mode: TraitQueryMode::Standard,
}
}
pub fn intercrate(infcx: &'cx InferCtxt<'tcx>) -> SelectionContext<'cx, 'tcx> {
SelectionContext { intercrate: true, ..SelectionContext::new(infcx) }
}
pub fn with_query_mode(
infcx: &'cx InferCtxt<'tcx>,
query_mode: TraitQueryMode,
@ -247,7 +223,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
/// Enables tracking of intercrate ambiguity causes. See
/// the documentation of [`Self::intercrate_ambiguity_causes`] for more.
pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
assert!(self.intercrate);
assert!(self.is_intercrate());
assert!(self.intercrate_ambiguity_causes.is_none());
self.intercrate_ambiguity_causes = Some(FxIndexSet::default());
debug!("selcx: enable_tracking_intercrate_ambiguity_causes");
@ -257,7 +233,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
/// was enabled and disables tracking at the same time. If
/// tracking is not enabled, just returns an empty vector.
pub fn take_intercrate_ambiguity_causes(&mut self) -> FxIndexSet<IntercrateAmbiguityCause> {
assert!(self.intercrate);
assert!(self.is_intercrate());
self.intercrate_ambiguity_causes.take().unwrap_or_default()
}
@ -270,7 +246,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
pub fn is_intercrate(&self) -> bool {
self.intercrate
self.infcx.intercrate
}
///////////////////////////////////////////////////////////////////////////
@ -741,6 +717,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("TypeWellFormedFromEnv is only used for chalk")
}
ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig),
}
})
}
@ -751,7 +728,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
previous_stack: TraitObligationStackList<'o, 'tcx>,
mut obligation: TraitObligation<'tcx>,
) -> Result<EvaluationResult, OverflowError> {
if !self.intercrate
if !self.is_intercrate()
&& obligation.is_global()
&& obligation.param_env.caller_bounds().iter().all(|bound| bound.needs_subst())
{
@ -1014,7 +991,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// mode, so don't do any caching. In particular, we might
// re-use the same `InferCtxt` with both an intercrate
// and non-intercrate `SelectionContext`
if self.intercrate {
if self.is_intercrate() {
return None;
}
@ -1044,7 +1021,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// mode, so don't do any caching. In particular, we might
// re-use the same `InferCtxt` with both an intercrate
// and non-intercrate `SelectionContext`
if self.intercrate {
if self.is_intercrate() {
return;
}
@ -1225,9 +1202,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Result<(), Conflict> {
debug!("is_knowable(intercrate={:?})", self.intercrate);
debug!("is_knowable(intercrate={:?})", self.is_intercrate());
if !self.intercrate || stack.obligation.polarity() == ty::ImplPolarity::Negative {
if !self.is_intercrate() || stack.obligation.polarity() == ty::ImplPolarity::Negative {
return Ok(());
}
@ -1258,7 +1235,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// the master cache. Since coherence executes pretty quickly,
// it's not worth going to more trouble to increase the
// hit-rate, I don't think.
if self.intercrate {
if self.is_intercrate() {
return false;
}
@ -1275,7 +1252,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// mode, so don't do any caching. In particular, we might
// re-use the same `InferCtxt` with both an intercrate
// and non-intercrate `SelectionContext`
if self.intercrate {
if self.is_intercrate() {
return None;
}
let tcx = self.tcx();
@ -1314,7 +1291,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// mode, so don't do any caching. In particular, we might
// re-use the same `InferCtxt` with both an intercrate
// and non-intercrate `SelectionContext`
if self.intercrate {
if self.is_intercrate() {
return false;
}
match result {
@ -2191,7 +2168,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{e}`"))?;
nested_obligations.extend(obligations);
if !self.intercrate
if !self.is_intercrate()
&& self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation
{
debug!("reservation impls only apply in intercrate mode");

View file

@ -155,6 +155,7 @@ pub fn predicate_obligations<'tcx>(
wf.compute(c1.into());
wf.compute(c2.into());
}
ty::PredicateKind::Ambiguous => {}
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("TypeWellFormedFromEnv is only used for Chalk")
}
@ -875,6 +876,7 @@ pub(crate) fn required_region_bounds<'tcx>(
| ty::PredicateKind::RegionOutlives(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::Ambiguous
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => {
// Search for a bound of the form `erased_self_ty