mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-02 15:32:06 +00:00
Auto merge of #55517 - nikomatsakis:universes, r=scalexm
Universes This PR transitions the compiler to use **universes** instead of the **leak-check**. It is marked as [WIP] for a few reasons: - The diagnostics at present are terrible =) - This changes the behavior of coherence, regressing some things that used to compile The goals of this PR at present are: - To start getting some eyes on the code - To do a crater run - To see the full travis results (due to https://github.com/rust-lang/rust/issues/52452, I am not able to run the full test suite locally anymore at present) The first few commits in the PR are changing how `evaluate` treats regions. We now track whether region comparisons occurred, reverting the "staticized" query approach that @arielb1 put in. The problem with "staticized" queries is that it relied on the leak-check to get higher-ranked things correct, and we are removing the leak-check in this PR series, so that caused problems. You can see at the end a collection of test updates. Mostly we behave the same but with atrocious diagnostics, but there are a number of cases where we used to error and now no longer do, as well as single case where we used to **not** error but we now do (the coherence-subtyping change). (Note: it would be possible to do a version of leak-check that propagates universe information and recover the old behavior. I am reluctant to do so because I'd like to leave us room to get more precise -- e.g., I want to eventually handle things like `exists<'a> { for<'b> { if ('a: 'b) { 'a: 'b } } }` which presently the leak-check cannot cope with etc. Also because it seems more consistent to me: most folks I've talked to expect the new behavior and are surprised to learn that binding sites were so significant before when it comes to coherence. One question is, though, to what extent are people relying on this in the wild?)
This commit is contained in:
commit
c0bbc3927e
@ -132,12 +132,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
ty::ReEmpty => ("the empty lifetime".to_owned(), None),
|
||||
|
||||
ty::RePlaceholder(_) => (format!("any other region"), None),
|
||||
|
||||
// FIXME(#13998) RePlaceholder should probably print like
|
||||
// ReFree rather than dumping Debug output on the user.
|
||||
//
|
||||
// We shouldn't really be having unification failures with ReVar
|
||||
// and ReLateBound though.
|
||||
ty::RePlaceholder(..) | ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
|
||||
ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
|
||||
(format!("lifetime {:?}", region), None)
|
||||
}
|
||||
|
||||
@ -324,8 +326,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
// the error. If all of these fails, we fall back to a rather
|
||||
// general bit of code that displays the error information
|
||||
RegionResolutionError::ConcreteFailure(origin, sub, sup) => {
|
||||
self.report_concrete_failure(region_scope_tree, origin, sub, sup)
|
||||
.emit();
|
||||
if sub.is_placeholder() || sup.is_placeholder() {
|
||||
self.report_placeholder_failure(region_scope_tree, origin, sub, sup)
|
||||
.emit();
|
||||
} else {
|
||||
self.report_concrete_failure(region_scope_tree, origin, sub, sup)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
RegionResolutionError::GenericBoundFailure(origin, param_ty, sub) => {
|
||||
@ -339,20 +346,39 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
RegionResolutionError::SubSupConflict(
|
||||
_,
|
||||
var_origin,
|
||||
sub_origin,
|
||||
sub_r,
|
||||
sup_origin,
|
||||
sup_r,
|
||||
) => {
|
||||
self.report_sub_sup_conflict(
|
||||
region_scope_tree,
|
||||
var_origin,
|
||||
sub_origin,
|
||||
sub_r,
|
||||
sup_origin,
|
||||
sup_r,
|
||||
);
|
||||
if sub_r.is_placeholder() {
|
||||
self.report_placeholder_failure(
|
||||
region_scope_tree,
|
||||
sub_origin,
|
||||
sub_r,
|
||||
sup_r,
|
||||
)
|
||||
.emit();
|
||||
} else if sup_r.is_placeholder() {
|
||||
self.report_placeholder_failure(
|
||||
region_scope_tree,
|
||||
sup_origin,
|
||||
sub_r,
|
||||
sup_r,
|
||||
)
|
||||
.emit();
|
||||
} else {
|
||||
self.report_sub_sup_conflict(
|
||||
region_scope_tree,
|
||||
var_origin,
|
||||
sub_origin,
|
||||
sub_r,
|
||||
sup_origin,
|
||||
sup_r,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -407,7 +433,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
errors.sort_by_key(|u| match *u {
|
||||
RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(),
|
||||
RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(),
|
||||
RegionResolutionError::SubSupConflict(ref rvo, _, _, _, _) => rvo.span(),
|
||||
RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _) => rvo.span(),
|
||||
});
|
||||
errors
|
||||
}
|
||||
@ -1306,6 +1332,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
match (&sup_origin, &sub_origin) {
|
||||
(&infer::Subtype(ref sup_trace), &infer::Subtype(ref sub_trace)) => {
|
||||
debug!("report_sub_sup_conflict: var_origin={:?}", var_origin);
|
||||
debug!("report_sub_sup_conflict: sub_region={:?}", sub_region);
|
||||
debug!("report_sub_sup_conflict: sub_origin={:?}", sub_origin);
|
||||
debug!("report_sub_sup_conflict: sup_region={:?}", sup_region);
|
||||
debug!("report_sub_sup_conflict: sup_origin={:?}", sup_origin);
|
||||
debug!("report_sub_sup_conflict: sup_trace={:?}", sup_trace);
|
||||
debug!("report_sub_sup_conflict: sub_trace={:?}", sub_trace);
|
||||
debug!("report_sub_sup_conflict: sup_trace.values={:?}", sup_trace.values);
|
||||
debug!("report_sub_sup_conflict: sub_trace.values={:?}", sub_trace.values);
|
||||
|
||||
if let (Some((sup_expected, sup_found)), Some((sub_expected, sub_found))) = (
|
||||
self.values_str(&sup_trace.values),
|
||||
self.values_str(&sub_trace.values),
|
||||
|
@ -8,6 +8,7 @@ use util::common::ErrorReported;
|
||||
mod different_lifetimes;
|
||||
mod find_anon_type;
|
||||
mod named_anon_conflict;
|
||||
mod placeholder_error;
|
||||
mod outlives_closure;
|
||||
mod static_impl_trait;
|
||||
mod util;
|
||||
@ -58,10 +59,11 @@ impl<'cx, 'gcx, 'tcx> NiceRegionError<'cx, 'gcx, 'tcx> {
|
||||
// Due to the improved diagnostics returned by the MIR borrow checker, only a subset of
|
||||
// the nice region errors are required when running under the MIR borrow checker.
|
||||
self.try_report_named_anon_conflict()
|
||||
.or_else(|| self.try_report_placeholder_conflict())
|
||||
}
|
||||
|
||||
pub fn try_report(&self) -> Option<ErrorReported> {
|
||||
self.try_report_named_anon_conflict()
|
||||
self.try_report_from_nll()
|
||||
.or_else(|| self.try_report_anon_anon_conflict())
|
||||
.or_else(|| self.try_report_outlives_closure())
|
||||
.or_else(|| self.try_report_static_impl_trait())
|
||||
@ -69,8 +71,8 @@ impl<'cx, 'gcx, 'tcx> NiceRegionError<'cx, 'gcx, 'tcx> {
|
||||
|
||||
pub fn get_regions(&self) -> (Span, ty::Region<'tcx>, ty::Region<'tcx>) {
|
||||
match (&self.error, self.regions) {
|
||||
(&Some(ConcreteFailure(ref origin, sub, sup)), None) => (origin.span(), sub, sup),
|
||||
(&Some(SubSupConflict(_, ref origin, sub, _, sup)), None) => (origin.span(), sub, sup),
|
||||
(Some(ConcreteFailure(origin, sub, sup)), None) => (origin.span(), sub, sup),
|
||||
(Some(SubSupConflict(_, _, origin, sub, _, sup)), None) => (origin.span(), sub, sup),
|
||||
(None, Some((span, sub, sup))) => (span, sub, sup),
|
||||
(Some(_), Some(_)) => panic!("incorrectly built NiceRegionError"),
|
||||
_ => panic!("trying to report on an incorrect lifetime failure"),
|
||||
|
@ -36,7 +36,8 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
|
||||
/// ...because it cannot outlive this closure
|
||||
/// ```
|
||||
pub(super) fn try_report_outlives_closure(&self) -> Option<ErrorReported> {
|
||||
if let Some(SubSupConflict(origin,
|
||||
if let Some(SubSupConflict(_,
|
||||
origin,
|
||||
ref sub_origin,
|
||||
_,
|
||||
ref sup_origin,
|
||||
|
@ -0,0 +1,307 @@
|
||||
use hir::def_id::DefId;
|
||||
use infer::error_reporting::nice_region_error::NiceRegionError;
|
||||
use infer::lexical_region_resolve::RegionResolutionError;
|
||||
use infer::ValuePairs;
|
||||
use infer::{SubregionOrigin, TypeTrace};
|
||||
use traits::{ObligationCause, ObligationCauseCode};
|
||||
use ty;
|
||||
use ty::error::ExpectedFound;
|
||||
use ty::subst::Substs;
|
||||
use util::common::ErrorReported;
|
||||
use util::ppaux::RegionHighlightMode;
|
||||
|
||||
impl NiceRegionError<'me, 'gcx, 'tcx> {
|
||||
/// When given a `ConcreteFailure` for a function with arguments containing a named region and
|
||||
/// an anonymous region, emit an descriptive diagnostic error.
|
||||
pub(super) fn try_report_placeholder_conflict(&self) -> Option<ErrorReported> {
|
||||
match &self.error {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// NB. The ordering of cases in this match is very
|
||||
// sensitive, because we are often matching against
|
||||
// specific cases and then using an `_` to match all
|
||||
// others.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Check for errors from comparing trait failures -- first
|
||||
// with two placeholders, then with one.
|
||||
Some(RegionResolutionError::SubSupConflict(
|
||||
vid,
|
||||
_,
|
||||
SubregionOrigin::Subtype(TypeTrace {
|
||||
cause,
|
||||
values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
|
||||
}),
|
||||
sub_placeholder @ ty::RePlaceholder(_),
|
||||
_,
|
||||
sup_placeholder @ ty::RePlaceholder(_),
|
||||
))
|
||||
if expected.def_id == found.def_id =>
|
||||
{
|
||||
Some(self.try_report_placeholders_trait(
|
||||
Some(self.tcx.mk_region(ty::ReVar(*vid))),
|
||||
cause,
|
||||
Some(sub_placeholder),
|
||||
Some(sup_placeholder),
|
||||
expected.def_id,
|
||||
expected.substs,
|
||||
found.substs,
|
||||
))
|
||||
}
|
||||
|
||||
Some(RegionResolutionError::SubSupConflict(
|
||||
vid,
|
||||
_,
|
||||
SubregionOrigin::Subtype(TypeTrace {
|
||||
cause,
|
||||
values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
|
||||
}),
|
||||
sub_placeholder @ ty::RePlaceholder(_),
|
||||
_,
|
||||
_,
|
||||
))
|
||||
if expected.def_id == found.def_id =>
|
||||
{
|
||||
Some(self.try_report_placeholders_trait(
|
||||
Some(self.tcx.mk_region(ty::ReVar(*vid))),
|
||||
cause,
|
||||
Some(sub_placeholder),
|
||||
None,
|
||||
expected.def_id,
|
||||
expected.substs,
|
||||
found.substs,
|
||||
))
|
||||
}
|
||||
|
||||
Some(RegionResolutionError::SubSupConflict(
|
||||
vid,
|
||||
_,
|
||||
SubregionOrigin::Subtype(TypeTrace {
|
||||
cause,
|
||||
values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
|
||||
}),
|
||||
_,
|
||||
_,
|
||||
sup_placeholder @ ty::RePlaceholder(_),
|
||||
))
|
||||
if expected.def_id == found.def_id =>
|
||||
{
|
||||
Some(self.try_report_placeholders_trait(
|
||||
Some(self.tcx.mk_region(ty::ReVar(*vid))),
|
||||
cause,
|
||||
None,
|
||||
Some(*sup_placeholder),
|
||||
expected.def_id,
|
||||
expected.substs,
|
||||
found.substs,
|
||||
))
|
||||
}
|
||||
|
||||
Some(RegionResolutionError::ConcreteFailure(
|
||||
SubregionOrigin::Subtype(TypeTrace {
|
||||
cause,
|
||||
values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
|
||||
}),
|
||||
sub_region @ ty::RePlaceholder(_),
|
||||
sup_region @ ty::RePlaceholder(_),
|
||||
))
|
||||
if expected.def_id == found.def_id =>
|
||||
{
|
||||
Some(self.try_report_placeholders_trait(
|
||||
None,
|
||||
cause,
|
||||
Some(*sub_region),
|
||||
Some(*sup_region),
|
||||
expected.def_id,
|
||||
expected.substs,
|
||||
found.substs,
|
||||
))
|
||||
}
|
||||
|
||||
Some(RegionResolutionError::ConcreteFailure(
|
||||
SubregionOrigin::Subtype(TypeTrace {
|
||||
cause,
|
||||
values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
|
||||
}),
|
||||
sub_region @ ty::RePlaceholder(_),
|
||||
sup_region,
|
||||
))
|
||||
if expected.def_id == found.def_id =>
|
||||
{
|
||||
Some(self.try_report_placeholders_trait(
|
||||
Some(sup_region),
|
||||
cause,
|
||||
Some(*sub_region),
|
||||
None,
|
||||
expected.def_id,
|
||||
expected.substs,
|
||||
found.substs,
|
||||
))
|
||||
}
|
||||
|
||||
Some(RegionResolutionError::ConcreteFailure(
|
||||
SubregionOrigin::Subtype(TypeTrace {
|
||||
cause,
|
||||
values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
|
||||
}),
|
||||
sub_region,
|
||||
sup_region @ ty::RePlaceholder(_),
|
||||
))
|
||||
if expected.def_id == found.def_id =>
|
||||
{
|
||||
Some(self.try_report_placeholders_trait(
|
||||
Some(sub_region),
|
||||
cause,
|
||||
None,
|
||||
Some(*sup_region),
|
||||
expected.def_id,
|
||||
expected.substs,
|
||||
found.substs,
|
||||
))
|
||||
}
|
||||
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
// error[E0308]: implementation of `Foo` does not apply to enough lifetimes
|
||||
// --> /home/nmatsakis/tmp/foo.rs:12:5
|
||||
// |
|
||||
// 12 | all::<&'static u32>();
|
||||
// | ^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
||||
// |
|
||||
// = note: Due to a where-clause on the function `all`,
|
||||
// = note: `T` must implement `...` for any two lifetimes `'1` and `'2`.
|
||||
// = note: However, the type `T` only implements `...` for some specific lifetime `'2`.
|
||||
fn try_report_placeholders_trait(
|
||||
&self,
|
||||
vid: Option<ty::Region<'tcx>>,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
sub_placeholder: Option<ty::Region<'tcx>>,
|
||||
sup_placeholder: Option<ty::Region<'tcx>>,
|
||||
trait_def_id: DefId,
|
||||
expected_substs: &'tcx Substs<'tcx>,
|
||||
actual_substs: &'tcx Substs<'tcx>,
|
||||
) -> ErrorReported {
|
||||
let mut err = self.tcx.sess.struct_span_err(
|
||||
cause.span(&self.tcx),
|
||||
&format!(
|
||||
"implementation of `{}` is not general enough",
|
||||
self.tcx.item_path_str(trait_def_id),
|
||||
),
|
||||
);
|
||||
|
||||
match cause.code {
|
||||
ObligationCauseCode::ItemObligation(def_id) => {
|
||||
err.note(&format!(
|
||||
"Due to a where-clause on `{}`,",
|
||||
self.tcx.item_path_str(def_id),
|
||||
));
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let expected_trait_ref = ty::TraitRef {
|
||||
def_id: trait_def_id,
|
||||
substs: expected_substs,
|
||||
};
|
||||
let actual_trait_ref = ty::TraitRef {
|
||||
def_id: trait_def_id,
|
||||
substs: actual_substs,
|
||||
};
|
||||
|
||||
// Search the expected and actual trait references to see (a)
|
||||
// whether the sub/sup placeholders appear in them (sometimes
|
||||
// you have a trait ref like `T: Foo<fn(&u8)>`, where the
|
||||
// placeholder was created as part of an inner type) and (b)
|
||||
// whether the inference variable appears. In each case,
|
||||
// assign a counter value in each case if so.
|
||||
let mut counter = 0;
|
||||
let mut has_sub = None;
|
||||
let mut has_sup = None;
|
||||
let mut has_vid = None;
|
||||
|
||||
self.tcx.for_each_free_region(&expected_trait_ref, |r| {
|
||||
if Some(r) == sub_placeholder && has_sub.is_none() {
|
||||
has_sub = Some(counter);
|
||||
counter += 1;
|
||||
} else if Some(r) == sup_placeholder && has_sup.is_none() {
|
||||
has_sup = Some(counter);
|
||||
counter += 1;
|
||||
}
|
||||
});
|
||||
|
||||
self.tcx.for_each_free_region(&actual_trait_ref, |r| {
|
||||
if Some(r) == vid && has_vid.is_none() {
|
||||
has_vid = Some(counter);
|
||||
counter += 1;
|
||||
}
|
||||
});
|
||||
|
||||
let self_ty_has_vid = self
|
||||
.tcx
|
||||
.any_free_region_meets(&actual_trait_ref.self_ty(), |r| Some(r) == vid);
|
||||
|
||||
RegionHighlightMode::maybe_highlighting_region(sub_placeholder, has_sub, || {
|
||||
RegionHighlightMode::maybe_highlighting_region(sup_placeholder, has_sup, || {
|
||||
match (has_sub, has_sup) {
|
||||
(Some(n1), Some(n2)) => {
|
||||
err.note(&format!(
|
||||
"`{}` must implement `{}` \
|
||||
for any two lifetimes `'{}` and `'{}`",
|
||||
expected_trait_ref.self_ty(),
|
||||
expected_trait_ref,
|
||||
std::cmp::min(n1, n2),
|
||||
std::cmp::max(n1, n2),
|
||||
));
|
||||
}
|
||||
(Some(n), _) | (_, Some(n)) => {
|
||||
err.note(&format!(
|
||||
"`{}` must implement `{}` \
|
||||
for any lifetime `'{}`",
|
||||
expected_trait_ref.self_ty(),
|
||||
expected_trait_ref,
|
||||
n,
|
||||
));
|
||||
}
|
||||
(None, None) => {
|
||||
err.note(&format!(
|
||||
"`{}` must implement `{}`",
|
||||
expected_trait_ref.self_ty(),
|
||||
expected_trait_ref,
|
||||
));
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
RegionHighlightMode::maybe_highlighting_region(vid, has_vid, || match has_vid {
|
||||
Some(n) => {
|
||||
if self_ty_has_vid {
|
||||
err.note(&format!(
|
||||
"but `{}` only implements `{}` for the lifetime `'{}`",
|
||||
actual_trait_ref.self_ty(),
|
||||
actual_trait_ref,
|
||||
n
|
||||
));
|
||||
} else {
|
||||
err.note(&format!(
|
||||
"but `{}` only implements `{}` for some lifetime `'{}`",
|
||||
actual_trait_ref.self_ty(),
|
||||
actual_trait_ref,
|
||||
n
|
||||
));
|
||||
}
|
||||
}
|
||||
None => {
|
||||
err.note(&format!(
|
||||
"but `{}` only implements `{}`",
|
||||
actual_trait_ref.self_ty(),
|
||||
actual_trait_ref,
|
||||
));
|
||||
}
|
||||
});
|
||||
|
||||
err.emit();
|
||||
ErrorReported
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
|
||||
pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
|
||||
if let Some(ref error) = self.error {
|
||||
if let RegionResolutionError::SubSupConflict(
|
||||
_,
|
||||
var_origin,
|
||||
sub_origin,
|
||||
sub_r,
|
||||
|
@ -442,4 +442,24 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn report_placeholder_failure(
|
||||
&self,
|
||||
region_scope_tree: ®ion::ScopeTree,
|
||||
placeholder_origin: SubregionOrigin<'tcx>,
|
||||
sub: Region<'tcx>,
|
||||
sup: Region<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
// I can't think how to do better than this right now. -nikomatsakis
|
||||
match placeholder_origin {
|
||||
infer::Subtype(trace) => {
|
||||
let terr = TypeError::RegionsPlaceholderMismatch;
|
||||
self.report_and_explain_type_error(trace, &terr)
|
||||
}
|
||||
|
||||
_ => {
|
||||
self.report_concrete_failure(region_scope_tree, placeholder_origin, sub, sup)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,31 +1,23 @@
|
||||
//! Helper routines for higher-ranked things. See the `doc` module at
|
||||
//! the end of the file for details.
|
||||
|
||||
use super::{CombinedSnapshot,
|
||||
InferCtxt,
|
||||
HigherRankedType,
|
||||
SubregionOrigin,
|
||||
PlaceholderMap};
|
||||
use super::combine::CombineFields;
|
||||
use super::region_constraints::{TaintDirections};
|
||||
use super::{HigherRankedType, InferCtxt, PlaceholderMap};
|
||||
|
||||
use ty::{self, TyCtxt, Binder, TypeFoldable};
|
||||
use ty::error::TypeError;
|
||||
use ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
use syntax_pos::Span;
|
||||
use util::nodemap::{FxHashMap, FxHashSet};
|
||||
|
||||
pub struct HrMatchResult<U> {
|
||||
pub value: U,
|
||||
}
|
||||
use ty::{self, Binder, TypeFoldable};
|
||||
|
||||
impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
|
||||
pub fn higher_ranked_sub<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool)
|
||||
-> RelateResult<'tcx, Binder<T>>
|
||||
where T: Relate<'tcx>
|
||||
pub fn higher_ranked_sub<T>(
|
||||
&mut self,
|
||||
a: &Binder<T>,
|
||||
b: &Binder<T>,
|
||||
a_is_expected: bool,
|
||||
) -> RelateResult<'tcx, Binder<T>>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
{
|
||||
debug!("higher_ranked_sub(a={:?}, b={:?})",
|
||||
a, b);
|
||||
debug!("higher_ranked_sub(a={:?}, b={:?})", a, b);
|
||||
|
||||
// Rather than checking the subtype relationship between `a` and `b`
|
||||
// as-is, we need to do some extra work here in order to make sure
|
||||
@ -35,279 +27,37 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
|
||||
// please see the large comment at the end of the file in the (inlined) module
|
||||
// `doc`.
|
||||
|
||||
// Start a snapshot so we can examine "all bindings that were
|
||||
// created as part of this type comparison".
|
||||
return self.infcx.commit_if_ok(|snapshot| {
|
||||
let span = self.trace.cause.span;
|
||||
let span = self.trace.cause.span;
|
||||
|
||||
// First, we instantiate each bound region in the supertype with a
|
||||
// fresh placeholder region.
|
||||
let (b_prime, placeholder_map) =
|
||||
self.infcx.replace_bound_vars_with_placeholders(b);
|
||||
// First, we instantiate each bound region in the supertype with a
|
||||
// fresh placeholder region.
|
||||
let (b_prime, _) = self.infcx.replace_bound_vars_with_placeholders(b);
|
||||
|
||||
// Next, we instantiate each bound region in the subtype
|
||||
// with a fresh region variable. These region variables --
|
||||
// but no other pre-existing region variables -- can name
|
||||
// the placeholders.
|
||||
let (a_prime, _) = self.infcx.replace_bound_vars_with_fresh_vars(
|
||||
span,
|
||||
HigherRankedType,
|
||||
a
|
||||
);
|
||||
// Next, we instantiate each bound region in the subtype
|
||||
// with a fresh region variable. These region variables --
|
||||
// but no other pre-existing region variables -- can name
|
||||
// the placeholders.
|
||||
let (a_prime, _) =
|
||||
self.infcx
|
||||
.replace_bound_vars_with_fresh_vars(span, HigherRankedType, a);
|
||||
|
||||
debug!("a_prime={:?}", a_prime);
|
||||
debug!("b_prime={:?}", b_prime);
|
||||
debug!("a_prime={:?}", a_prime);
|
||||
debug!("b_prime={:?}", b_prime);
|
||||
|
||||
// Compare types now that bound regions have been replaced.
|
||||
let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?;
|
||||
// Compare types now that bound regions have been replaced.
|
||||
let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?;
|
||||
|
||||
// Presuming type comparison succeeds, we need to check
|
||||
// that the placeholder regions do not "leak".
|
||||
self.infcx.leak_check(!a_is_expected, span, &placeholder_map, snapshot)?;
|
||||
debug!("higher_ranked_sub: OK result={:?}", result);
|
||||
|
||||
// We are finished with the placeholder regions now so pop
|
||||
// them off.
|
||||
self.infcx.pop_placeholders(placeholder_map, snapshot);
|
||||
|
||||
debug!("higher_ranked_sub: OK result={:?}", result);
|
||||
|
||||
Ok(ty::Binder::bind(result))
|
||||
});
|
||||
Ok(ty::Binder::bind(result))
|
||||
}
|
||||
|
||||
/// The value consists of a pair `(t, u)` where `t` is the
|
||||
/// *matcher* and `u` is a *value*. The idea is to find a
|
||||
/// substitution `S` such that `S(t) == b`, and then return
|
||||
/// `S(u)`. In other words, find values for the late-bound regions
|
||||
/// in `a` that can make `t == b` and then replace the LBR in `u`
|
||||
/// with those values.
|
||||
///
|
||||
/// This routine is (as of this writing) used in trait matching,
|
||||
/// particularly projection.
|
||||
///
|
||||
/// NB. It should not happen that there are LBR appearing in `U`
|
||||
/// that do not appear in `T`. If that happens, those regions are
|
||||
/// unconstrained, and this routine replaces them with `'static`.
|
||||
pub fn higher_ranked_match<T, U>(&mut self,
|
||||
a_pair: &Binder<(T, U)>,
|
||||
b_match: &T,
|
||||
a_is_expected: bool)
|
||||
-> RelateResult<'tcx, HrMatchResult<U>>
|
||||
where T: Relate<'tcx>,
|
||||
U: TypeFoldable<'tcx>
|
||||
{
|
||||
debug!("higher_ranked_match(a={:?}, b={:?})",
|
||||
a_pair, b_match);
|
||||
|
||||
// Start a snapshot so we can examine "all bindings that were
|
||||
// created as part of this type comparison".
|
||||
return self.infcx.commit_if_ok(|snapshot| {
|
||||
// First, we instantiate each bound region in the matcher
|
||||
// with a placeholder region.
|
||||
let ((a_match, a_value), placeholder_map) =
|
||||
self.infcx.replace_bound_vars_with_placeholders(a_pair);
|
||||
|
||||
debug!("higher_ranked_match: a_match={:?}", a_match);
|
||||
debug!("higher_ranked_match: placeholder_map={:?}", placeholder_map);
|
||||
|
||||
// Equate types now that bound regions have been replaced.
|
||||
self.equate(a_is_expected).relate(&a_match, &b_match)?;
|
||||
|
||||
// Map each placeholder region to a vector of other regions that it
|
||||
// must be equated with. (Note that this vector may include other
|
||||
// placeholder regions from `placeholder_map`.)
|
||||
let placeholder_resolution_map: FxHashMap<_, _> =
|
||||
placeholder_map
|
||||
.iter()
|
||||
.map(|(&br, &placeholder)| {
|
||||
let tainted_regions =
|
||||
self.infcx.tainted_regions(snapshot,
|
||||
placeholder,
|
||||
TaintDirections::incoming()); // [1]
|
||||
|
||||
// [1] this routine executes after the placeholder
|
||||
// regions have been *equated* with something
|
||||
// else, so examining the incoming edges ought to
|
||||
// be enough to collect all constraints
|
||||
|
||||
(placeholder, (br, tainted_regions))
|
||||
})
|
||||
.collect();
|
||||
|
||||
// For each placeholder region, pick a representative -- which can
|
||||
// be any region from the sets above, except for other members of
|
||||
// `placeholder_map`. There should always be a representative if things
|
||||
// are properly well-formed.
|
||||
let placeholder_representatives: FxHashMap<_, _> =
|
||||
placeholder_resolution_map
|
||||
.iter()
|
||||
.map(|(&placeholder, &(_, ref regions))| {
|
||||
let representative =
|
||||
regions.iter()
|
||||
.filter(|&&r| !placeholder_resolution_map.contains_key(r))
|
||||
.cloned()
|
||||
.next()
|
||||
.unwrap_or_else(|| {
|
||||
bug!("no representative region for `{:?}` in `{:?}`",
|
||||
placeholder, regions)
|
||||
});
|
||||
|
||||
(placeholder, representative)
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Equate all the members of each placeholder set with the
|
||||
// representative.
|
||||
for (placeholder, &(_br, ref regions)) in &placeholder_resolution_map {
|
||||
let representative = &placeholder_representatives[placeholder];
|
||||
debug!("higher_ranked_match: \
|
||||
placeholder={:?} representative={:?} regions={:?}",
|
||||
placeholder, representative, regions);
|
||||
for region in regions.iter()
|
||||
.filter(|&r| !placeholder_resolution_map.contains_key(r))
|
||||
.filter(|&r| r != representative)
|
||||
{
|
||||
let origin = SubregionOrigin::Subtype(self.trace.clone());
|
||||
self.infcx.borrow_region_constraints()
|
||||
.make_eqregion(origin,
|
||||
*representative,
|
||||
*region);
|
||||
}
|
||||
}
|
||||
|
||||
// Replace the placeholder regions appearing in value with
|
||||
// their representatives
|
||||
let a_value =
|
||||
fold_regions_in(
|
||||
self.tcx(),
|
||||
&a_value,
|
||||
|r, _| placeholder_representatives.get(&r).cloned().unwrap_or(r));
|
||||
|
||||
debug!("higher_ranked_match: value={:?}", a_value);
|
||||
|
||||
// We are now done with these placeholder variables.
|
||||
self.infcx.pop_placeholders(placeholder_map, snapshot);
|
||||
|
||||
Ok(HrMatchResult { value: a_value })
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_regions_in<'a, 'gcx, 'tcx, T, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
unbound_value: &T,
|
||||
mut fldr: F)
|
||||
-> T
|
||||
where T: TypeFoldable<'tcx>,
|
||||
F: FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>,
|
||||
{
|
||||
tcx.fold_regions(unbound_value, &mut false, |region, current_depth| {
|
||||
// we should only be encountering "escaping" late-bound regions here,
|
||||
// because the ones at the current level should have been replaced
|
||||
// with fresh variables
|
||||
assert!(match *region {
|
||||
ty::ReLateBound(..) => false,
|
||||
_ => true
|
||||
});
|
||||
|
||||
fldr(region, current_depth)
|
||||
})
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
fn tainted_regions(&self,
|
||||
snapshot: &CombinedSnapshot<'a, 'tcx>,
|
||||
r: ty::Region<'tcx>,
|
||||
directions: TaintDirections)
|
||||
-> FxHashSet<ty::Region<'tcx>> {
|
||||
self.borrow_region_constraints().tainted(
|
||||
self.tcx,
|
||||
&snapshot.region_constraints_snapshot,
|
||||
r,
|
||||
directions)
|
||||
}
|
||||
|
||||
fn region_vars_confined_to_snapshot(&self,
|
||||
snapshot: &CombinedSnapshot<'a, 'tcx>)
|
||||
-> Vec<ty::RegionVid>
|
||||
{
|
||||
/*!
|
||||
* Returns the set of region variables that do not affect any
|
||||
* types/regions which existed before `snapshot` was
|
||||
* started. This is used in the sub/lub/glb computations. The
|
||||
* idea here is that when we are computing lub/glb of two
|
||||
* regions, we sometimes create intermediate region variables.
|
||||
* Those region variables may touch some of the placeholder or
|
||||
* other "forbidden" regions we created to replace bound
|
||||
* regions, but they don't really represent an "external"
|
||||
* constraint.
|
||||
*
|
||||
* However, sometimes fresh variables are created for other
|
||||
* purposes too, and those *may* represent an external
|
||||
* constraint. In particular, when a type variable is
|
||||
* instantiated, we create region variables for all the
|
||||
* regions that appear within, and if that type variable
|
||||
* pre-existed the snapshot, then those region variables
|
||||
* represent external constraints.
|
||||
*
|
||||
* An example appears in the unit test
|
||||
* `sub_free_bound_false_infer`. In this test, we want to
|
||||
* know whether
|
||||
*
|
||||
* ```rust
|
||||
* fn(_#0t) <: for<'a> fn(&'a int)
|
||||
* ```
|
||||
*
|
||||
* Note that the subtype has a type variable. Because the type
|
||||
* variable can't be instantiated with a region that is bound
|
||||
* in the fn signature, this comparison ought to fail. But if
|
||||
* we're not careful, it will succeed.
|
||||
*
|
||||
* The reason is that when we walk through the subtyping
|
||||
* algorithm, we begin by replacing `'a` with a placeholder
|
||||
* variable `'1`. We then have `fn(_#0t) <: fn(&'1 int)`. This
|
||||
* can be made true by unifying `_#0t` with `&'1 int`. In the
|
||||
* process, we create a fresh variable for the placeholder
|
||||
* region, `'$2`, and hence we have that `_#0t == &'$2
|
||||
* int`. However, because `'$2` was created during the sub
|
||||
* computation, if we're not careful we will erroneously
|
||||
* assume it is one of the transient region variables
|
||||
* representing a lub/glb internally. Not good.
|
||||
*
|
||||
* To prevent this, we check for type variables which were
|
||||
* unified during the snapshot, and say that any region
|
||||
* variable created during the snapshot but which finds its
|
||||
* way into a type variable is considered to "escape" the
|
||||
* snapshot.
|
||||
*/
|
||||
|
||||
let mut region_vars =
|
||||
self.borrow_region_constraints().vars_created_since_snapshot(
|
||||
&snapshot.region_constraints_snapshot);
|
||||
|
||||
let escaping_types =
|
||||
self.type_variables.borrow_mut().types_escaping_snapshot(&snapshot.type_snapshot);
|
||||
|
||||
let mut escaping_region_vars = FxHashSet::default();
|
||||
for ty in &escaping_types {
|
||||
self.tcx.collect_regions(ty, &mut escaping_region_vars);
|
||||
}
|
||||
|
||||
region_vars.retain(|®ion_vid| {
|
||||
let r = ty::ReVar(region_vid);
|
||||
!escaping_region_vars.contains(&r)
|
||||
});
|
||||
|
||||
debug!("region_vars_confined_to_snapshot: region_vars={:?} escaping_types={:?}",
|
||||
region_vars,
|
||||
escaping_types);
|
||||
|
||||
region_vars
|
||||
}
|
||||
|
||||
/// Replace all regions (resp. types) bound by `binder` with placeholder
|
||||
/// regions (resp. types) and return a map indicating which bound-region
|
||||
/// was replaced with what placeholder region. This is the first step of
|
||||
/// checking subtyping when higher-ranked things are involved.
|
||||
/// placeholder region. This is the first step of checking subtyping
|
||||
/// when higher-ranked things are involved.
|
||||
///
|
||||
/// **Important:** you must call this function from within a snapshot.
|
||||
/// Moreover, before committing the snapshot, you must eventually call
|
||||
@ -354,201 +104,4 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
(result, map)
|
||||
}
|
||||
|
||||
/// Searches the region constraints created since `snapshot` was started
|
||||
/// and checks to determine whether any of the placeholder regions created
|
||||
/// in `placeholder_map` would "escape" -- meaning that they are related to
|
||||
/// other regions in some way. If so, the higher-ranked subtyping doesn't
|
||||
/// hold. See `README.md` for more details.
|
||||
pub fn leak_check(&self,
|
||||
overly_polymorphic: bool,
|
||||
_span: Span,
|
||||
placeholder_map: &PlaceholderMap<'tcx>,
|
||||
snapshot: &CombinedSnapshot<'a, 'tcx>)
|
||||
-> RelateResult<'tcx, ()>
|
||||
{
|
||||
debug!("leak_check: placeholder_map={:?}",
|
||||
placeholder_map);
|
||||
|
||||
// If the user gave `-Zno-leak-check`, then skip the leak
|
||||
// check completely. This is wildly unsound and also not
|
||||
// unlikely to cause an ICE or two. It is intended for use
|
||||
// only during a transition period, in which the MIR typeck
|
||||
// uses the "universe-style" check, and the rest of typeck
|
||||
// uses the more conservative leak check. Since the leak
|
||||
// check is more conservative, we can't test the
|
||||
// universe-style check without disabling it.
|
||||
if self.tcx.sess.opts.debugging_opts.no_leak_check {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let new_vars = self.region_vars_confined_to_snapshot(snapshot);
|
||||
for (&placeholder_br, &placeholder) in placeholder_map {
|
||||
// The inputs to a placeholder variable can only
|
||||
// be itself or other new variables.
|
||||
let incoming_taints = self.tainted_regions(snapshot,
|
||||
placeholder,
|
||||
TaintDirections::both());
|
||||
for &tainted_region in &incoming_taints {
|
||||
// Each placeholder should only be relatable to itself
|
||||
// or new variables:
|
||||
match *tainted_region {
|
||||
ty::ReVar(vid) => {
|
||||
if new_vars.contains(&vid) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if tainted_region == placeholder { continue; }
|
||||
}
|
||||
};
|
||||
|
||||
debug!("{:?} (which replaced {:?}) is tainted by {:?}",
|
||||
placeholder,
|
||||
placeholder_br,
|
||||
tainted_region);
|
||||
|
||||
return Err(if overly_polymorphic {
|
||||
debug!("Overly polymorphic!");
|
||||
TypeError::RegionsOverlyPolymorphic(placeholder_br, tainted_region)
|
||||
} else {
|
||||
debug!("Not as polymorphic!");
|
||||
TypeError::RegionsInsufficientlyPolymorphic(placeholder_br, tainted_region)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// This code converts from placeholder regions back to late-bound
|
||||
/// regions. It works by replacing each region in the taint set of a
|
||||
/// placeholder region with a bound-region. The bound region will be bound
|
||||
/// by the outer-most binder in `value`; the caller must ensure that there is
|
||||
/// such a binder and it is the right place.
|
||||
///
|
||||
/// This routine is only intended to be used when the leak-check has
|
||||
/// passed; currently, it's used in the trait matching code to create
|
||||
/// a set of nested obligations from an impl that matches against
|
||||
/// something higher-ranked. More details can be found in
|
||||
/// `librustc/middle/traits/README.md`.
|
||||
///
|
||||
/// As a brief example, consider the obligation `for<'a> Fn(&'a int)
|
||||
/// -> &'a int`, and the impl:
|
||||
///
|
||||
/// impl<A,R> Fn<A,R> for SomethingOrOther
|
||||
/// where A : Clone
|
||||
/// { ... }
|
||||
///
|
||||
/// Here we will have replaced `'a` with a placeholder region
|
||||
/// `'0`. This means that our substitution will be `{A=>&'0
|
||||
/// int, R=>&'0 int}`.
|
||||
///
|
||||
/// When we apply the substitution to the bounds, we will wind up with
|
||||
/// `&'0 int : Clone` as a predicate. As a last step, we then go and
|
||||
/// replace `'0` with a late-bound region `'a`. The depth is matched
|
||||
/// to the depth of the predicate, in this case 1, so that the final
|
||||
/// predicate is `for<'a> &'a int : Clone`.
|
||||
pub fn plug_leaks<T>(&self,
|
||||
placeholder_map: PlaceholderMap<'tcx>,
|
||||
snapshot: &CombinedSnapshot<'a, 'tcx>,
|
||||
value: T) -> T
|
||||
where T : TypeFoldable<'tcx>
|
||||
{
|
||||
debug!("plug_leaks(placeholder_map={:?}, value={:?})",
|
||||
placeholder_map,
|
||||
value);
|
||||
|
||||
if placeholder_map.is_empty() {
|
||||
return value;
|
||||
}
|
||||
|
||||
// Compute a mapping from the "taint set" of each placeholder
|
||||
// region back to the `ty::BoundRegion` that it originally
|
||||
// represented. Because `leak_check` passed, we know that
|
||||
// these taint sets are mutually disjoint.
|
||||
let inv_placeholder_map: FxHashMap<ty::Region<'tcx>, ty::BoundRegion> =
|
||||
placeholder_map
|
||||
.iter()
|
||||
.flat_map(|(&placeholder_br, &placeholder)| {
|
||||
self.tainted_regions(snapshot, placeholder, TaintDirections::both())
|
||||
.into_iter()
|
||||
.map(move |tainted_region| (tainted_region, placeholder_br))
|
||||
})
|
||||
.collect();
|
||||
|
||||
debug!("plug_leaks: inv_placeholder_map={:?}",
|
||||
inv_placeholder_map);
|
||||
|
||||
// Remove any instantiated type variables from `value`; those can hide
|
||||
// references to regions from the `fold_regions` code below.
|
||||
let value = self.resolve_type_vars_if_possible(&value);
|
||||
|
||||
// Map any placeholder byproducts back to a late-bound
|
||||
// region. Put that late-bound region at whatever the outermost
|
||||
// binder is that we encountered in `value`. The caller is
|
||||
// responsible for ensuring that (a) `value` contains at least one
|
||||
// binder and (b) that binder is the one we want to use.
|
||||
let result = self.tcx.fold_regions(&value, &mut false, |r, current_depth| {
|
||||
match inv_placeholder_map.get(&r) {
|
||||
None => r,
|
||||
Some(br) => {
|
||||
// It is the responsibility of the caller to ensure
|
||||
// that each placeholder region appears within a
|
||||
// binder. In practice, this routine is only used by
|
||||
// trait checking, and all of the placeholder regions
|
||||
// appear inside predicates, which always have
|
||||
// binders, so this assert is satisfied.
|
||||
assert!(current_depth > ty::INNERMOST);
|
||||
|
||||
// since leak-check passed, this placeholder region
|
||||
// should only have incoming edges from variables
|
||||
// (which ought not to escape the snapshot, but we
|
||||
// don't check that) or itself
|
||||
assert!(
|
||||
match *r {
|
||||
ty::ReVar(_) => true,
|
||||
ty::RePlaceholder(index) => index.name == *br,
|
||||
_ => false,
|
||||
},
|
||||
"leak-check would have us replace {:?} with {:?}",
|
||||
r, br);
|
||||
|
||||
self.tcx.mk_region(ty::ReLateBound(
|
||||
current_depth.shifted_out(1),
|
||||
br.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
self.pop_placeholders(placeholder_map, snapshot);
|
||||
|
||||
debug!("plug_leaks: result={:?}", result);
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Pops the placeholder regions found in `placeholder_map` from the region
|
||||
/// inference context. Whenever you create placeholder regions via
|
||||
/// `replace_bound_vars_with_placeholders`, they must be popped before you
|
||||
/// commit the enclosing snapshot (if you do not commit, e.g., within a
|
||||
/// probe or as a result of an error, then this is not necessary, as
|
||||
/// popping happens as part of the rollback).
|
||||
///
|
||||
/// Note: popping also occurs implicitly as part of `leak_check`.
|
||||
pub fn pop_placeholders(
|
||||
&self,
|
||||
placeholder_map: PlaceholderMap<'tcx>,
|
||||
snapshot: &CombinedSnapshot<'a, 'tcx>,
|
||||
) {
|
||||
debug!("pop_placeholders({:?})", placeholder_map);
|
||||
let placeholder_regions: FxHashSet<_> = placeholder_map.values().cloned().collect();
|
||||
self.borrow_region_constraints().pop_placeholders(&placeholder_regions);
|
||||
self.universe.set(snapshot.universe);
|
||||
if !placeholder_map.is_empty() {
|
||||
self.projection_cache.borrow_mut().rollback_placeholder(
|
||||
&snapshot.projection_cache_snapshot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,12 +73,13 @@ pub enum RegionResolutionError<'tcx> {
|
||||
/// `a` (but none of the known bounds are sufficient).
|
||||
GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region<'tcx>),
|
||||
|
||||
/// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`:
|
||||
/// `SubSupConflict(v, v_origin, sub_origin, sub_r, sup_origin, sup_r)`:
|
||||
///
|
||||
/// Could not infer a value for `v` because `sub_r <= v` (due to
|
||||
/// `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and
|
||||
/// Could not infer a value for `v` (which has origin `v_origin`)
|
||||
/// because `sub_r <= v` (due to `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and
|
||||
/// `sub_r <= sup_r` does not hold.
|
||||
SubSupConflict(
|
||||
RegionVid,
|
||||
RegionVariableOrigin,
|
||||
SubregionOrigin<'tcx>,
|
||||
Region<'tcx>,
|
||||
@ -215,23 +216,41 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
||||
) -> bool {
|
||||
debug!("expand_node({:?}, {:?} == {:?})", a_region, b_vid, b_data);
|
||||
|
||||
// Check if this relationship is implied by a given.
|
||||
match *a_region {
|
||||
// Check if this relationship is implied by a given.
|
||||
ty::ReEarlyBound(_) | ty::ReFree(_) => if self.data.givens.contains(&(a_region, b_vid))
|
||||
{
|
||||
debug!("given");
|
||||
return false;
|
||||
},
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
||||
match *b_data {
|
||||
VarValue::Value(cur_region) => {
|
||||
let lub = self.lub_concrete_regions(a_region, cur_region);
|
||||
let mut lub = self.lub_concrete_regions(a_region, cur_region);
|
||||
if lub == cur_region {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Watch out for `'b: !1` relationships, where the
|
||||
// universe of `'b` can't name the placeholder `!1`. In
|
||||
// that case, we have to grow `'b` to be `'static` for the
|
||||
// relationship to hold. This is obviously a kind of sub-optimal
|
||||
// choice -- in the future, when we incorporate a knowledge
|
||||
// of the parameter environment, we might be able to find a
|
||||
// tighter bound than `'static`.
|
||||
//
|
||||
// (This might e.g. arise from being asked to prove `for<'a> { 'b: 'a }`.)
|
||||
let b_universe = self.var_infos[b_vid].universe;
|
||||
if let ty::RePlaceholder(p) = lub {
|
||||
if b_universe.cannot_name(p.universe) {
|
||||
lub = self.tcx().types.re_static;
|
||||
}
|
||||
}
|
||||
|
||||
debug!(
|
||||
"Expanding value of {:?} from {:?} to {:?}",
|
||||
b_vid, cur_region, lub
|
||||
@ -554,10 +573,22 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
||||
lower_bounds.sort_by_key(region_order_key);
|
||||
upper_bounds.sort_by_key(region_order_key);
|
||||
|
||||
let node_universe = self.var_infos[node_idx].universe;
|
||||
|
||||
for lower_bound in &lower_bounds {
|
||||
let effective_lower_bound = if let ty::RePlaceholder(p) = lower_bound.region {
|
||||
if node_universe.cannot_name(p.universe) {
|
||||
self.tcx().types.re_static
|
||||
} else {
|
||||
lower_bound.region
|
||||
}
|
||||
} else {
|
||||
lower_bound.region
|
||||
};
|
||||
|
||||
for upper_bound in &upper_bounds {
|
||||
if !self.region_rels
|
||||
.is_subregion_of(lower_bound.region, upper_bound.region)
|
||||
.is_subregion_of(effective_lower_bound, upper_bound.region)
|
||||
{
|
||||
let origin = self.var_infos[node_idx].origin.clone();
|
||||
debug!(
|
||||
@ -566,6 +597,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
||||
origin, node_idx, lower_bound.region, upper_bound.region
|
||||
);
|
||||
errors.push(RegionResolutionError::SubSupConflict(
|
||||
node_idx,
|
||||
origin,
|
||||
lower_bound.origin.clone(),
|
||||
lower_bound.region,
|
||||
@ -580,9 +612,10 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
||||
span_bug!(
|
||||
self.var_infos[node_idx].origin.span(),
|
||||
"collect_error_for_expanding_node() could not find \
|
||||
error for var {:?}, lower_bounds={:?}, \
|
||||
upper_bounds={:?}",
|
||||
error for var {:?} in universe {:?}, lower_bounds={:#?}, \
|
||||
upper_bounds={:#?}",
|
||||
node_idx,
|
||||
node_universe,
|
||||
lower_bounds,
|
||||
upper_bounds
|
||||
);
|
||||
|
@ -32,7 +32,6 @@ use ty::{FloatVid, IntVid, TyVid};
|
||||
use util::nodemap::FxHashMap;
|
||||
|
||||
use self::combine::CombineFields;
|
||||
use self::higher_ranked::HrMatchResult;
|
||||
use self::lexical_region_resolve::LexicalRegionResolutions;
|
||||
use self::outlives::env::OutlivesEnvironment;
|
||||
use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, VerifyBound};
|
||||
@ -226,7 +225,7 @@ pub struct InferCtxt<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||
pub type PlaceholderMap<'tcx> = BTreeMap<ty::BoundRegion, ty::Region<'tcx>>;
|
||||
|
||||
/// See `error_reporting` module for more details
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum ValuePairs<'tcx> {
|
||||
Types(ExpectedFound<Ty<'tcx>>),
|
||||
Regions(ExpectedFound<ty::Region<'tcx>>),
|
||||
@ -868,6 +867,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
r
|
||||
}
|
||||
|
||||
/// Scan the constraints produced since `snapshot` began and returns:
|
||||
///
|
||||
/// - None -- if none of them involve "region outlives" constraints
|
||||
/// - Some(true) -- if there are `'a: 'b` constraints where `'a` or `'b` is a placehodler
|
||||
/// - Some(false) -- if there are `'a: 'b` constraints but none involve placeholders
|
||||
pub fn region_constraints_added_in_snapshot(
|
||||
&self,
|
||||
snapshot: &CombinedSnapshot<'a, 'tcx>,
|
||||
) -> Option<bool> {
|
||||
self.borrow_region_constraints().region_constraints_added_in_snapshot(
|
||||
&snapshot.region_constraints_snapshot,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn add_given(&self, sub: ty::Region<'tcx>, sup: ty::RegionVid) {
|
||||
self.borrow_region_constraints().add_given(sub, sup);
|
||||
}
|
||||
@ -939,39 +952,32 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(self.commit_if_ok(|snapshot| {
|
||||
let (
|
||||
ty::SubtypePredicate {
|
||||
a_is_expected,
|
||||
a,
|
||||
b,
|
||||
},
|
||||
placeholder_map,
|
||||
) = self.replace_bound_vars_with_placeholders(predicate);
|
||||
let (
|
||||
ty::SubtypePredicate {
|
||||
a_is_expected,
|
||||
a,
|
||||
b,
|
||||
},
|
||||
_,
|
||||
) = self.replace_bound_vars_with_placeholders(predicate);
|
||||
|
||||
let cause_span = cause.span;
|
||||
let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?;
|
||||
self.leak_check(false, cause_span, &placeholder_map, snapshot)?;
|
||||
self.pop_placeholders(placeholder_map, snapshot);
|
||||
Ok(ok.unit())
|
||||
}))
|
||||
Some(
|
||||
self.at(cause, param_env)
|
||||
.sub_exp(a_is_expected, a, b)
|
||||
.map(|ok| ok.unit()),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn region_outlives_predicate(
|
||||
&self,
|
||||
cause: &traits::ObligationCause<'tcx>,
|
||||
predicate: &ty::PolyRegionOutlivesPredicate<'tcx>,
|
||||
) -> UnitResult<'tcx> {
|
||||
self.commit_if_ok(|snapshot| {
|
||||
let (ty::OutlivesPredicate(r_a, r_b), placeholder_map) =
|
||||
self.replace_bound_vars_with_placeholders(predicate);
|
||||
let origin = SubregionOrigin::from_obligation_cause(cause, || {
|
||||
RelateRegionParamBound(cause.span)
|
||||
});
|
||||
self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
|
||||
self.leak_check(false, cause.span, &placeholder_map, snapshot)?;
|
||||
Ok(self.pop_placeholders(placeholder_map, snapshot))
|
||||
})
|
||||
) {
|
||||
let (ty::OutlivesPredicate(r_a, r_b), _) =
|
||||
self.replace_bound_vars_with_placeholders(predicate);
|
||||
let origin =
|
||||
SubregionOrigin::from_obligation_cause(cause, || RelateRegionParamBound(cause.span));
|
||||
self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
|
||||
}
|
||||
|
||||
pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid {
|
||||
@ -1380,46 +1386,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
self.tcx.replace_bound_vars(value, fld_r, fld_t)
|
||||
}
|
||||
|
||||
/// Given a higher-ranked projection predicate like:
|
||||
///
|
||||
/// for<'a> <T as Fn<&'a u32>>::Output = &'a u32
|
||||
///
|
||||
/// and a target trait-ref like:
|
||||
///
|
||||
/// <T as Fn<&'x u32>>
|
||||
///
|
||||
/// find a substitution `S` for the higher-ranked regions (here,
|
||||
/// `['a => 'x]`) such that the predicate matches the trait-ref,
|
||||
/// and then return the value (here, `&'a u32`) but with the
|
||||
/// substitution applied (hence, `&'x u32`).
|
||||
///
|
||||
/// See `higher_ranked_match` in `higher_ranked/mod.rs` for more
|
||||
/// details.
|
||||
pub fn match_poly_projection_predicate(
|
||||
&self,
|
||||
cause: ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
match_a: ty::PolyProjectionPredicate<'tcx>,
|
||||
match_b: ty::TraitRef<'tcx>,
|
||||
) -> InferResult<'tcx, HrMatchResult<Ty<'tcx>>> {
|
||||
let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref(self.tcx), p.ty));
|
||||
let trace = TypeTrace {
|
||||
cause,
|
||||
values: TraitRefs(ExpectedFound::new(
|
||||
true,
|
||||
match_pair.skip_binder().0,
|
||||
match_b,
|
||||
)),
|
||||
};
|
||||
|
||||
let mut combine = self.combine_fields(trace, param_env);
|
||||
let result = combine.higher_ranked_match(&match_pair, &match_b, true)?;
|
||||
Ok(InferOk {
|
||||
value: result,
|
||||
obligations: combine.obligations,
|
||||
})
|
||||
}
|
||||
|
||||
/// See `verify_generic_bound` method in `region_constraints`
|
||||
pub fn verify_generic_bound(
|
||||
&self,
|
||||
@ -1434,18 +1400,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
.verify_generic_bound(origin, kind, a, bound);
|
||||
}
|
||||
|
||||
pub fn type_moves_by_default(
|
||||
pub fn type_is_copy_modulo_regions(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
) -> bool {
|
||||
let ty = self.resolve_type_vars_if_possible(&ty);
|
||||
|
||||
// Even if the type may have no inference variables, during
|
||||
// type-checking closure types are in local tables only.
|
||||
if !self.in_progress_tables.is_some() || !ty.has_closure_types() {
|
||||
if let Some((param_env, ty)) = self.tcx.lift_to_global(&(param_env, ty)) {
|
||||
return ty.moves_by_default(self.tcx.global_tcx(), param_env, span);
|
||||
return ty.is_copy_modulo_regions(self.tcx.global_tcx(), param_env, span);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1455,7 +1422,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
// rightly refuses to work with inference variables, but
|
||||
// moves_by_default has a cache, which we want to use in other
|
||||
// cases.
|
||||
!traits::type_known_to_meet_bound(self, param_env, ty, copy_def_id, span)
|
||||
traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span)
|
||||
}
|
||||
|
||||
/// Obtains the latest type of the given closure; this may be a
|
||||
|
@ -17,8 +17,6 @@ use ty::{Region, RegionVid};
|
||||
use std::collections::BTreeMap;
|
||||
use std::{cmp, fmt, mem, u32};
|
||||
|
||||
mod taint;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct RegionConstraintCollector<'tcx> {
|
||||
/// For each `RegionVid`, the corresponding `RegionVariableOrigin`.
|
||||
@ -130,6 +128,16 @@ pub enum Constraint<'tcx> {
|
||||
RegSubReg(Region<'tcx>, Region<'tcx>),
|
||||
}
|
||||
|
||||
impl Constraint<'_> {
|
||||
pub fn involves_placeholders(&self) -> bool {
|
||||
match self {
|
||||
Constraint::VarSubVar(_, _) => false,
|
||||
Constraint::VarSubReg(_, r) | Constraint::RegSubVar(r, _) => r.is_placeholder(),
|
||||
Constraint::RegSubReg(r, s) => r.is_placeholder() || s.is_placeholder(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// VerifyGenericBound(T, _, R, RS): The parameter type `T` (or
|
||||
/// associated type) must outlive the region `R`. `T` is known to
|
||||
/// outlive `RS`. Therefore verify that `R <= RS[i]` for some
|
||||
@ -326,6 +334,8 @@ impl TaintDirections {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ConstraintInfo {}
|
||||
|
||||
impl<'tcx> RegionConstraintCollector<'tcx> {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
@ -487,7 +497,8 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
|
||||
) -> RegionVid {
|
||||
let vid = self.var_infos.push(RegionVariableInfo { origin, universe });
|
||||
|
||||
let u_vid = self.unification_table
|
||||
let u_vid = self
|
||||
.unification_table
|
||||
.new_key(unify_key::RegionVidKey { min_vid: vid });
|
||||
assert_eq!(vid, u_vid);
|
||||
if self.in_snapshot() {
|
||||
@ -519,7 +530,8 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
|
||||
|
||||
assert!(self.in_snapshot());
|
||||
|
||||
let constraints_to_kill: Vec<usize> = self.undo_log
|
||||
let constraints_to_kill: Vec<usize> = self
|
||||
.undo_log
|
||||
.iter()
|
||||
.enumerate()
|
||||
.rev()
|
||||
@ -822,37 +834,18 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
|
||||
.filter_map(|&elt| match elt {
|
||||
AddVar(vid) => Some(vid),
|
||||
_ => None,
|
||||
})
|
||||
.collect()
|
||||
}).collect()
|
||||
}
|
||||
|
||||
/// Computes all regions that have been related to `r0` since the
|
||||
/// mark `mark` was made---`r0` itself will be the first
|
||||
/// entry. The `directions` parameter controls what kind of
|
||||
/// relations are considered. For example, one can say that only
|
||||
/// "incoming" edges to `r0` are desired, in which case one will
|
||||
/// get the set of regions `{r|r <= r0}`. This is used when
|
||||
/// checking whether placeholder regions are being improperly
|
||||
/// related to other regions.
|
||||
pub fn tainted(
|
||||
&self,
|
||||
tcx: TyCtxt<'_, '_, 'tcx>,
|
||||
mark: &RegionSnapshot,
|
||||
r0: Region<'tcx>,
|
||||
directions: TaintDirections,
|
||||
) -> FxHashSet<ty::Region<'tcx>> {
|
||||
debug!(
|
||||
"tainted(mark={:?}, r0={:?}, directions={:?})",
|
||||
mark, r0, directions
|
||||
);
|
||||
|
||||
// `result_set` acts as a worklist: we explore all outgoing
|
||||
// edges and add any new regions we find to result_set. This
|
||||
// is not a terribly efficient implementation.
|
||||
let mut taint_set = taint::TaintSet::new(directions, r0);
|
||||
taint_set.fixed_point(tcx, &self.undo_log[mark.length..], &self.data.verifys);
|
||||
debug!("tainted: result={:?}", taint_set);
|
||||
return taint_set.into_set();
|
||||
/// See [`RegionInference::region_constraints_added_in_snapshot`]
|
||||
pub fn region_constraints_added_in_snapshot(&self, mark: &RegionSnapshot) -> Option<bool> {
|
||||
self.undo_log[mark.length..]
|
||||
.iter()
|
||||
.map(|&elt| match elt {
|
||||
AddConstraint(constraint) => Some(constraint.involves_placeholders()),
|
||||
_ => None,
|
||||
}).max()
|
||||
.unwrap_or(None)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,85 +0,0 @@
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct TaintSet<'tcx> {
|
||||
directions: TaintDirections,
|
||||
regions: FxHashSet<ty::Region<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> TaintSet<'tcx> {
|
||||
pub(super) fn new(directions: TaintDirections, initial_region: ty::Region<'tcx>) -> Self {
|
||||
let mut regions = FxHashSet::default();
|
||||
regions.insert(initial_region);
|
||||
TaintSet {
|
||||
directions: directions,
|
||||
regions: regions,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn fixed_point(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'_, '_, 'tcx>,
|
||||
undo_log: &[UndoLog<'tcx>],
|
||||
verifys: &[Verify<'tcx>],
|
||||
) {
|
||||
let mut prev_len = 0;
|
||||
while prev_len < self.len() {
|
||||
debug!(
|
||||
"tainted: prev_len = {:?} new_len = {:?}",
|
||||
prev_len,
|
||||
self.len()
|
||||
);
|
||||
|
||||
prev_len = self.len();
|
||||
|
||||
for undo_entry in undo_log {
|
||||
match undo_entry {
|
||||
&AddConstraint(Constraint::VarSubVar(a, b)) => {
|
||||
self.add_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b)));
|
||||
}
|
||||
&AddConstraint(Constraint::RegSubVar(a, b)) => {
|
||||
self.add_edge(a, tcx.mk_region(ReVar(b)));
|
||||
}
|
||||
&AddConstraint(Constraint::VarSubReg(a, b)) => {
|
||||
self.add_edge(tcx.mk_region(ReVar(a)), b);
|
||||
}
|
||||
&AddConstraint(Constraint::RegSubReg(a, b)) => {
|
||||
self.add_edge(a, b);
|
||||
}
|
||||
&AddGiven(a, b) => {
|
||||
self.add_edge(a, tcx.mk_region(ReVar(b)));
|
||||
}
|
||||
&AddVerify(i) => {
|
||||
span_bug!(
|
||||
verifys[i].origin.span(),
|
||||
"we never add verifications while doing higher-ranked things",
|
||||
)
|
||||
}
|
||||
&Purged | &AddCombination(..) | &AddVar(..) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn into_set(self) -> FxHashSet<ty::Region<'tcx>> {
|
||||
self.regions
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.regions.len()
|
||||
}
|
||||
|
||||
fn add_edge(&mut self, source: ty::Region<'tcx>, target: ty::Region<'tcx>) {
|
||||
if self.directions.incoming {
|
||||
if self.regions.contains(&target) {
|
||||
self.regions.insert(source);
|
||||
}
|
||||
}
|
||||
|
||||
if self.directions.outgoing {
|
||||
if self.regions.contains(&source) {
|
||||
self.regions.insert(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -976,7 +976,7 @@ fn copy_or_move<'a, 'gcx, 'tcx>(mc: &mc::MemCategorizationContext<'a, 'gcx, 'tcx
|
||||
move_reason: MoveReason)
|
||||
-> ConsumeMode
|
||||
{
|
||||
if mc.type_moves_by_default(param_env, cmt.ty, cmt.span) {
|
||||
if !mc.type_is_copy_modulo_regions(param_env, cmt.ty, cmt.span) {
|
||||
Move(move_reason)
|
||||
} else {
|
||||
Copy
|
||||
|
@ -443,15 +443,16 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_moves_by_default(&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
span: Span)
|
||||
-> bool {
|
||||
self.infcx.map(|infcx| infcx.type_moves_by_default(param_env, ty, span))
|
||||
pub fn type_is_copy_modulo_regions(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
) -> bool {
|
||||
self.infcx.map(|infcx| infcx.type_is_copy_modulo_regions(param_env, ty, span))
|
||||
.or_else(|| {
|
||||
self.tcx.lift_to_global(&(param_env, ty)).map(|(param_env, ty)| {
|
||||
ty.moves_by_default(self.tcx.global_tcx(), param_env, span)
|
||||
ty.is_copy_modulo_regions(self.tcx.global_tcx(), param_env, span)
|
||||
})
|
||||
})
|
||||
.unwrap_or(true)
|
||||
|
@ -771,13 +771,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
&ty::Predicate::RegionOutlives(ref binder) => {
|
||||
if select
|
||||
.infcx()
|
||||
.region_outlives_predicate(&dummy_cause, binder)
|
||||
.is_err()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
let () = select.infcx().region_outlives_predicate(&dummy_cause, binder);
|
||||
}
|
||||
&ty::Predicate::TypeOutlives(ref binder) => {
|
||||
match (
|
||||
|
@ -4,6 +4,7 @@
|
||||
//! [trait-resolution]: https://rust-lang.github.io/rustc-guide/traits/resolution.html
|
||||
//! [trait-specialization]: https://rust-lang.github.io/rustc-guide/traits/specialization.html
|
||||
|
||||
use infer::CombinedSnapshot;
|
||||
use hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use syntax_pos::DUMMY_SP;
|
||||
use traits::{self, Normalized, SelectionContext, Obligation, ObligationCause};
|
||||
@ -33,6 +34,17 @@ pub enum Conflict {
|
||||
pub struct OverlapResult<'tcx> {
|
||||
pub impl_header: ty::ImplHeader<'tcx>,
|
||||
pub intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>,
|
||||
|
||||
/// True if the overlap might've been permitted before the shift
|
||||
/// to universes.
|
||||
pub involves_placeholder: bool,
|
||||
}
|
||||
|
||||
pub fn add_placeholder_note(err: &mut ::errors::DiagnosticBuilder<'_>) {
|
||||
err.note(&format!(
|
||||
"this behavior recently changed as a result of a bug fix; \
|
||||
see rust-lang/rust#56105 for details"
|
||||
));
|
||||
}
|
||||
|
||||
/// If there are types that satisfy both impls, invokes `on_overlap`
|
||||
@ -104,13 +116,22 @@ fn with_fresh_ty_vars<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, '
|
||||
|
||||
/// Can both impl `a` and impl `b` be satisfied by a common type (including
|
||||
/// `where` clauses)? If so, returns an `ImplHeader` that unifies the two impls.
|
||||
fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
||||
a_def_id: DefId,
|
||||
b_def_id: DefId)
|
||||
-> Option<OverlapResult<'tcx>>
|
||||
{
|
||||
fn overlap<'cx, 'gcx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
||||
a_def_id: DefId,
|
||||
b_def_id: DefId,
|
||||
) -> Option<OverlapResult<'tcx>> {
|
||||
debug!("overlap(a_def_id={:?}, b_def_id={:?})", a_def_id, b_def_id);
|
||||
|
||||
selcx.infcx().probe(|snapshot| overlap_within_probe(selcx, a_def_id, b_def_id, snapshot))
|
||||
}
|
||||
|
||||
fn overlap_within_probe(
|
||||
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
||||
a_def_id: DefId,
|
||||
b_def_id: DefId,
|
||||
snapshot: &CombinedSnapshot<'_, 'tcx>,
|
||||
) -> Option<OverlapResult<'tcx>> {
|
||||
// For the purposes of this check, we don't bring any placeholder
|
||||
// types into scope; instead, we replace the generic types with
|
||||
// fresh type variables, and hence we do our evaluations in an
|
||||
@ -158,7 +179,13 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
||||
let impl_header = selcx.infcx().resolve_type_vars_if_possible(&a_impl_header);
|
||||
let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes();
|
||||
debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes);
|
||||
Some(OverlapResult { impl_header, intercrate_ambiguity_causes })
|
||||
|
||||
let involves_placeholder = match selcx.infcx().region_constraints_added_in_snapshot(snapshot) {
|
||||
Some(true) => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder })
|
||||
}
|
||||
|
||||
pub fn trait_ref_is_knowable<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
|
@ -728,12 +728,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
ty::Predicate::RegionOutlives(ref predicate) => {
|
||||
let predicate = self.resolve_type_vars_if_possible(predicate);
|
||||
let err = self.region_outlives_predicate(&obligation.cause,
|
||||
&predicate).err().unwrap();
|
||||
struct_span_err!(self.tcx.sess, span, E0279,
|
||||
"the requirement `{}` is not satisfied (`{}`)",
|
||||
predicate, err)
|
||||
// These errors should show up as region
|
||||
// inference failures.
|
||||
panic!("region outlives {:?} failed", predicate);
|
||||
}
|
||||
|
||||
ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
|
||||
|
@ -282,7 +282,7 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
|
||||
if data.is_global() {
|
||||
// no type variables present, can use evaluation for better caching.
|
||||
// FIXME: consider caching errors too.
|
||||
if self.selcx.infcx().predicate_must_hold(&obligation) {
|
||||
if self.selcx.infcx().predicate_must_hold_considering_regions(&obligation) {
|
||||
debug!("selecting trait `{:?}` at depth {} evaluated to holds",
|
||||
data, obligation.recursion_depth);
|
||||
return ProcessResult::Changed(vec![])
|
||||
@ -331,10 +331,8 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
|
||||
}
|
||||
|
||||
ty::Predicate::RegionOutlives(ref binder) => {
|
||||
match self.selcx.infcx().region_outlives_predicate(&obligation.cause, binder) {
|
||||
Ok(()) => ProcessResult::Changed(vec![]),
|
||||
Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)),
|
||||
}
|
||||
let () = self.selcx.infcx().region_outlives_predicate(&obligation.cause, binder);
|
||||
ProcessResult::Changed(vec![])
|
||||
}
|
||||
|
||||
ty::Predicate::TypeOutlives(ref binder) => {
|
||||
|
@ -43,7 +43,8 @@ pub use self::FulfillmentErrorCode::*;
|
||||
pub use self::Vtable::*;
|
||||
pub use self::ObligationCauseCode::*;
|
||||
|
||||
pub use self::coherence::{orphan_check, overlapping_impls, OrphanCheckErr, OverlapResult};
|
||||
pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls};
|
||||
pub use self::coherence::{OrphanCheckErr, OverlapResult};
|
||||
pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation};
|
||||
pub use self::project::MismatchedProjectionTypes;
|
||||
pub use self::project::{normalize, normalize_projection_type, poly_project_and_unify_type};
|
||||
@ -628,14 +629,14 @@ pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>,
|
||||
/// `bound` or is not known to meet bound (note that this is
|
||||
/// conservative towards *no impl*, which is the opposite of the
|
||||
/// `evaluate` methods).
|
||||
pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
def_id: DefId,
|
||||
span: Span)
|
||||
-> bool
|
||||
{
|
||||
debug!("type_known_to_meet_bound(ty={:?}, bound={:?})",
|
||||
pub fn type_known_to_meet_bound_modulo_regions<'a, 'gcx, 'tcx>(
|
||||
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
def_id: DefId,
|
||||
span: Span,
|
||||
) -> bool {
|
||||
debug!("type_known_to_meet_bound_modulo_regions(ty={:?}, bound={:?})",
|
||||
ty,
|
||||
infcx.tcx.item_path_str(def_id));
|
||||
|
||||
@ -650,7 +651,7 @@ pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx
|
||||
predicate: trait_ref.to_predicate(),
|
||||
};
|
||||
|
||||
let result = infcx.predicate_must_hold(&obligation);
|
||||
let result = infcx.predicate_must_hold_modulo_regions(&obligation);
|
||||
debug!("type_known_to_meet_ty={:?} bound={} => {:?}",
|
||||
ty, infcx.tcx.item_path_str(def_id), result);
|
||||
|
||||
@ -677,13 +678,13 @@ pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx
|
||||
// assume it is move; linear is always ok.
|
||||
match fulfill_cx.select_all_or_error(infcx) {
|
||||
Ok(()) => {
|
||||
debug!("type_known_to_meet_bound: ty={:?} bound={} success",
|
||||
debug!("type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success",
|
||||
ty,
|
||||
infcx.tcx.item_path_str(def_id));
|
||||
true
|
||||
}
|
||||
Err(e) => {
|
||||
debug!("type_known_to_meet_bound: ty={:?} bound={} errors={:?}",
|
||||
debug!("type_known_to_meet_bound_modulo_regions: ty={:?} bound={} errors={:?}",
|
||||
ty,
|
||||
infcx.tcx.item_path_str(def_id),
|
||||
e);
|
||||
|
@ -568,7 +568,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
|
||||
|
||||
self.infer_ctxt().enter(|ref infcx| {
|
||||
// the receiver is dispatchable iff the obligation holds
|
||||
infcx.predicate_must_hold(&obligation)
|
||||
infcx.predicate_must_hold_modulo_regions(&obligation)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ use super::{VtableImplData, VtableClosureData, VtableGeneratorData, VtableFnPoin
|
||||
use super::util;
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use infer::{InferCtxt, InferOk};
|
||||
use infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
|
||||
use infer::type_variable::TypeVariableOrigin;
|
||||
use mir::interpret::ConstValue;
|
||||
use mir::interpret::{GlobalId};
|
||||
@ -192,28 +192,12 @@ pub fn poly_project_and_unify_type<'cx, 'gcx, 'tcx>(
|
||||
obligation);
|
||||
|
||||
let infcx = selcx.infcx();
|
||||
infcx.commit_if_ok(|snapshot| {
|
||||
let (placeholder_predicate, placeholder_map) =
|
||||
infcx.commit_if_ok(|_| {
|
||||
let (placeholder_predicate, _) =
|
||||
infcx.replace_bound_vars_with_placeholders(&obligation.predicate);
|
||||
|
||||
let skol_obligation = obligation.with(placeholder_predicate);
|
||||
let r = match project_and_unify_type(selcx, &skol_obligation) {
|
||||
Ok(result) => {
|
||||
let span = obligation.cause.span;
|
||||
match infcx.leak_check(false, span, &placeholder_map, snapshot) {
|
||||
Ok(()) => Ok(infcx.plug_leaks(placeholder_map, snapshot, result)),
|
||||
Err(e) => {
|
||||
debug!("poly_project_and_unify_type: leak check encountered error {:?}", e);
|
||||
Err(MismatchedProjectionTypes { err: e })
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
Err(e)
|
||||
}
|
||||
};
|
||||
|
||||
r
|
||||
let placeholder_obligation = obligation.with(placeholder_predicate);
|
||||
project_and_unify_type(selcx, &placeholder_obligation)
|
||||
})
|
||||
}
|
||||
|
||||
@ -1443,17 +1427,25 @@ fn confirm_callable_candidate<'cx, 'gcx, 'tcx>(
|
||||
fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
poly_projection: ty::PolyProjectionPredicate<'tcx>)
|
||||
poly_cache_entry: ty::PolyProjectionPredicate<'tcx>)
|
||||
-> Progress<'tcx>
|
||||
{
|
||||
let infcx = selcx.infcx();
|
||||
let cause = obligation.cause.clone();
|
||||
let cause = &obligation.cause;
|
||||
let param_env = obligation.param_env;
|
||||
let trait_ref = obligation.predicate.trait_ref(infcx.tcx);
|
||||
match infcx.match_poly_projection_predicate(cause, param_env, poly_projection, trait_ref) {
|
||||
Ok(InferOk { value: ty_match, obligations }) => {
|
||||
|
||||
let (cache_entry, _) =
|
||||
infcx.replace_bound_vars_with_fresh_vars(
|
||||
cause.span,
|
||||
LateBoundRegionConversionTime::HigherRankedType,
|
||||
&poly_cache_entry);
|
||||
|
||||
let cache_trait_ref = cache_entry.projection_ty.trait_ref(infcx.tcx);
|
||||
let obligation_trait_ref = obligation.predicate.trait_ref(infcx.tcx);
|
||||
match infcx.at(cause, param_env).eq(cache_trait_ref, obligation_trait_ref) {
|
||||
Ok(InferOk { value: _, obligations }) => {
|
||||
Progress {
|
||||
ty: ty_match.value,
|
||||
ty: cache_entry.ty,
|
||||
obligations,
|
||||
}
|
||||
}
|
||||
@ -1463,7 +1455,7 @@ fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>(
|
||||
"Failed to unify obligation `{:?}` \
|
||||
with poly_projection `{:?}`: {:?}",
|
||||
obligation,
|
||||
poly_projection,
|
||||
poly_cache_entry,
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
@ -16,11 +16,26 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
||||
/// Evaluates whether the predicate can be satisfied in the given
|
||||
/// `ParamEnv`, and returns `false` if not certain. However, this is
|
||||
/// not entirely accurate if inference variables are involved.
|
||||
pub fn predicate_must_hold(
|
||||
///
|
||||
/// This version may conservatively fail when outlives obligations
|
||||
/// are required.
|
||||
pub fn predicate_must_hold_considering_regions(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
) -> bool {
|
||||
self.evaluate_obligation_no_overflow(obligation) == EvaluationResult::EvaluatedToOk
|
||||
self.evaluate_obligation_no_overflow(obligation).must_apply_considering_regions()
|
||||
}
|
||||
|
||||
/// Evaluates whether the predicate can be satisfied in the given
|
||||
/// `ParamEnv`, and returns `false` if not certain. However, this is
|
||||
/// not entirely accurate if inference variables are involved.
|
||||
///
|
||||
/// This version ignores all outlives constraints.
|
||||
pub fn predicate_must_hold_modulo_regions(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
) -> bool {
|
||||
self.evaluate_obligation_no_overflow(obligation).must_apply_modulo_regions()
|
||||
}
|
||||
|
||||
/// Evaluate a given predicate, capturing overflow and propagating it back.
|
||||
|
@ -29,7 +29,6 @@ use super::{
|
||||
|
||||
use dep_graph::{DepKind, DepNodeIndex};
|
||||
use hir::def_id::DefId;
|
||||
use infer;
|
||||
use infer::{InferCtxt, InferOk, TypeFreshener};
|
||||
use middle::lang_items;
|
||||
use mir::interpret::GlobalId;
|
||||
@ -45,7 +44,6 @@ use rustc_target::spec::abi::Abi;
|
||||
use std::cmp;
|
||||
use std::fmt;
|
||||
use std::iter;
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
use util::nodemap::{FxHashMap, FxHashSet};
|
||||
|
||||
@ -328,7 +326,8 @@ enum BuiltinImplConditions<'tcx> {
|
||||
/// evaluations.
|
||||
///
|
||||
/// The evaluation results are ordered:
|
||||
/// - `EvaluatedToOk` implies `EvaluatedToAmbig` implies `EvaluatedToUnknown`
|
||||
/// - `EvaluatedToOk` implies `EvaluatedToOkModuloRegions`
|
||||
/// implies `EvaluatedToAmbig` implies `EvaluatedToUnknown`
|
||||
/// - `EvaluatedToErr` implies `EvaluatedToRecur`
|
||||
/// - the "union" of evaluation results is equal to their maximum -
|
||||
/// all the "potential success" candidates can potentially succeed,
|
||||
@ -337,6 +336,8 @@ enum BuiltinImplConditions<'tcx> {
|
||||
pub enum EvaluationResult {
|
||||
/// Evaluation successful
|
||||
EvaluatedToOk,
|
||||
/// Evaluation successful, but there were unevaluated region obligations
|
||||
EvaluatedToOkModuloRegions,
|
||||
/// Evaluation is known to be ambiguous - it *might* hold for some
|
||||
/// assignment of inference variables, but it might not.
|
||||
///
|
||||
@ -400,9 +401,23 @@ pub enum EvaluationResult {
|
||||
}
|
||||
|
||||
impl EvaluationResult {
|
||||
/// True if this evaluation result is known to apply, even
|
||||
/// considering outlives constraints.
|
||||
pub fn must_apply_considering_regions(self) -> bool {
|
||||
self == EvaluatedToOk
|
||||
}
|
||||
|
||||
/// True if this evaluation result is known to apply, ignoring
|
||||
/// outlives constraints.
|
||||
pub fn must_apply_modulo_regions(self) -> bool {
|
||||
self <= EvaluatedToOkModuloRegions
|
||||
}
|
||||
|
||||
pub fn may_apply(self) -> bool {
|
||||
match self {
|
||||
EvaluatedToOk | EvaluatedToAmbig | EvaluatedToUnknown => true,
|
||||
EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToUnknown => {
|
||||
true
|
||||
}
|
||||
|
||||
EvaluatedToErr | EvaluatedToRecur => false,
|
||||
}
|
||||
@ -412,13 +427,14 @@ impl EvaluationResult {
|
||||
match self {
|
||||
EvaluatedToUnknown | EvaluatedToRecur => true,
|
||||
|
||||
EvaluatedToOk | EvaluatedToAmbig | EvaluatedToErr => false,
|
||||
EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToErr => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(enum self::EvaluationResult {
|
||||
EvaluatedToOk,
|
||||
EvaluatedToOkModuloRegions,
|
||||
EvaluatedToAmbig,
|
||||
EvaluatedToUnknown,
|
||||
EvaluatedToRecur,
|
||||
@ -531,33 +547,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
self.infcx
|
||||
}
|
||||
|
||||
/// Wraps the inference context's in_snapshot s.t. snapshot handling is only from the selection
|
||||
/// context's self.
|
||||
fn in_snapshot<R, F>(&mut self, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&mut Self, &infer::CombinedSnapshot<'cx, 'tcx>) -> R,
|
||||
{
|
||||
self.infcx.in_snapshot(|snapshot| f(self, snapshot))
|
||||
}
|
||||
|
||||
/// Wraps a probe s.t. obligations collected during it are ignored and old obligations are
|
||||
/// retained.
|
||||
fn probe<R, F>(&mut self, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&mut Self, &infer::CombinedSnapshot<'cx, 'tcx>) -> R,
|
||||
{
|
||||
self.infcx.probe(|snapshot| f(self, snapshot))
|
||||
}
|
||||
|
||||
/// Wraps a commit_if_ok s.t. obligations collected during it are not returned in selection if
|
||||
/// the transaction fails and s.t. old obligations are retained.
|
||||
fn commit_if_ok<T, E, F>(&mut self, f: F) -> Result<T, E>
|
||||
where
|
||||
F: FnOnce(&mut Self, &infer::CombinedSnapshot<'cx, 'tcx>) -> Result<T, E>,
|
||||
{
|
||||
self.infcx.commit_if_ok(|snapshot| f(self, snapshot))
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Selection
|
||||
//
|
||||
@ -639,11 +628,24 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
&mut self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
) -> Result<EvaluationResult, OverflowError> {
|
||||
self.probe(|this, _| {
|
||||
self.evaluation_probe(|this| {
|
||||
this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation)
|
||||
})
|
||||
}
|
||||
|
||||
fn evaluation_probe(
|
||||
&mut self,
|
||||
op: impl FnOnce(&mut Self) -> Result<EvaluationResult, OverflowError>,
|
||||
) -> Result<EvaluationResult, OverflowError> {
|
||||
self.infcx.probe(|snapshot| -> Result<EvaluationResult, OverflowError> {
|
||||
let result = op(self)?;
|
||||
match self.infcx.region_constraints_added_in_snapshot(snapshot) {
|
||||
None => Ok(result),
|
||||
Some(_) => Ok(result.max(EvaluatedToOkModuloRegions)),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Evaluates the predicates in `predicates` recursively. Note that
|
||||
/// this applies projections in the predicates, and therefore
|
||||
/// is run within an inference probe.
|
||||
@ -714,92 +716,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
None => Ok(EvaluatedToAmbig),
|
||||
},
|
||||
|
||||
ty::Predicate::TypeOutlives(ref binder) => {
|
||||
assert!(!binder.has_escaping_bound_vars());
|
||||
// Check if the type has higher-ranked vars.
|
||||
if binder.skip_binder().0.has_escaping_bound_vars() {
|
||||
// If so, this obligation is an error (for now). Eventually we should be
|
||||
// able to support additional cases here, like `for<'a> &'a str: 'a`.
|
||||
|
||||
// NOTE: this hack is implemented in both trait fulfillment and
|
||||
// evaluation. If you fix it in one place, make sure you fix it
|
||||
// in the other.
|
||||
|
||||
// We don't want to allow this sort of reasoning in intercrate
|
||||
// mode, for backwards-compatibility reasons.
|
||||
if self.intercrate.is_some() {
|
||||
Ok(EvaluatedToAmbig)
|
||||
} else {
|
||||
Ok(EvaluatedToErr)
|
||||
}
|
||||
} else {
|
||||
// If the type has no late bound vars, then if we assign all
|
||||
// the inference variables in it to be 'static, then the type
|
||||
// will be 'static itself.
|
||||
//
|
||||
// Therefore, `staticize(T): 'a` holds for any `'a`, so this
|
||||
// obligation is fulfilled. Because evaluation works with
|
||||
// staticized types (yes I know this is involved with #21974),
|
||||
// we are 100% OK here.
|
||||
Ok(EvaluatedToOk)
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::RegionOutlives(ref binder) => {
|
||||
let ty::OutlivesPredicate(r_a, r_b) = binder.skip_binder();
|
||||
|
||||
if r_a == r_b {
|
||||
// for<'a> 'a: 'a. OK
|
||||
Ok(EvaluatedToOk)
|
||||
} else if **r_a == ty::ReStatic {
|
||||
// 'static: 'x always holds.
|
||||
//
|
||||
// This special case is handled somewhat inconsistently - if we
|
||||
// have an inference variable that is supposed to be equal to
|
||||
// `'static`, then we don't allow it to be equated to an LBR,
|
||||
// but if we have a literal `'static`, then we *do*.
|
||||
//
|
||||
// This is actually consistent with how our region inference works.
|
||||
//
|
||||
// It would appear that this sort of inconsistency would
|
||||
// cause "instability" problems with evaluation caching. However,
|
||||
// evaluation caching is only for trait predicates, and when
|
||||
// trait predicates create nested obligations, they contain
|
||||
// inference variables for all the regions in the trait - the
|
||||
// only way this codepath can be reached from trait predicate
|
||||
// evaluation is when the user typed an explicit `where 'static: 'a`
|
||||
// lifetime bound (in which case we want to return EvaluatedToOk).
|
||||
//
|
||||
// If we ever want to handle inference variables that might be
|
||||
// equatable with ReStatic, we need to make sure we are not confused by
|
||||
// technically-allowed-by-RFC-447-but-probably-should-not-be
|
||||
// impls such as
|
||||
// ```Rust
|
||||
// impl<'a, 's, T> X<'s> for T where T: Debug + 'a, 'a: 's
|
||||
// ```
|
||||
Ok(EvaluatedToOk)
|
||||
} else if r_a.is_late_bound() || r_b.is_late_bound() {
|
||||
// There is no current way to prove `for<'a> 'a: 'x`
|
||||
// unless `'a = 'x`, because there are no bounds involving
|
||||
// lifetimes.
|
||||
|
||||
// It might be possible to prove `for<'a> 'x: 'a` by forcing `'x`
|
||||
// to be `'static`. However, this is not currently done by type
|
||||
// inference unless `'x` is literally ReStatic. See the comment
|
||||
// above.
|
||||
|
||||
// We don't want to allow this sort of reasoning in intercrate
|
||||
// mode, for backwards-compatibility reasons.
|
||||
if self.intercrate.is_some() {
|
||||
Ok(EvaluatedToAmbig)
|
||||
} else {
|
||||
Ok(EvaluatedToErr)
|
||||
}
|
||||
} else {
|
||||
// Relating 2 inference variable regions. These will
|
||||
// always hold if our query is "staticized".
|
||||
Ok(EvaluatedToOk)
|
||||
}
|
||||
ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => {
|
||||
// we do not consider region relationships when
|
||||
// evaluating trait matches
|
||||
Ok(EvaluatedToOkModuloRegions)
|
||||
}
|
||||
|
||||
ty::Predicate::ObjectSafe(trait_def_id) => {
|
||||
@ -1013,6 +933,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
{
|
||||
debug!("evaluate_stack({:?}) --> recursive", stack.fresh_trait_ref);
|
||||
|
||||
// Subtle: when checking for a coinductive cycle, we do
|
||||
// not compare using the "freshened trait refs" (which
|
||||
// have erased regions) but rather the fully explicit
|
||||
// trait refs. This is important because it's only a cycle
|
||||
// if the regions match exactly.
|
||||
let cycle = stack.iter().skip(1).take(rec_index + 1);
|
||||
let cycle = cycle.map(|stack| ty::Predicate::Trait(stack.obligation.predicate));
|
||||
if self.coinductive_match(cycle) {
|
||||
@ -1075,7 +1000,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
"evaluate_candidate: depth={} candidate={:?}",
|
||||
stack.obligation.recursion_depth, candidate
|
||||
);
|
||||
let result = self.probe(|this, _| {
|
||||
let result = self.evaluation_probe(|this| {
|
||||
let candidate = (*candidate).clone();
|
||||
match this.confirm_candidate(stack.obligation, candidate) {
|
||||
Ok(selection) => this.evaluate_predicates_recursively(
|
||||
@ -1706,8 +1631,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
_ => return,
|
||||
}
|
||||
|
||||
let result = self.probe(|this, snapshot| {
|
||||
this.match_projection_obligation_against_definition_bounds(obligation, snapshot)
|
||||
let result = self.infcx.probe(|_| {
|
||||
self.match_projection_obligation_against_definition_bounds(obligation)
|
||||
});
|
||||
|
||||
if result {
|
||||
@ -1718,16 +1643,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
fn match_projection_obligation_against_definition_bounds(
|
||||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
snapshot: &infer::CombinedSnapshot<'cx, 'tcx>,
|
||||
) -> bool {
|
||||
let poly_trait_predicate = self.infcx()
|
||||
.resolve_type_vars_if_possible(&obligation.predicate);
|
||||
let (skol_trait_predicate, placeholder_map) = self.infcx()
|
||||
let (skol_trait_predicate, _) = self.infcx()
|
||||
.replace_bound_vars_with_placeholders(&poly_trait_predicate);
|
||||
debug!(
|
||||
"match_projection_obligation_against_definition_bounds: \
|
||||
skol_trait_predicate={:?} placeholder_map={:?}",
|
||||
skol_trait_predicate, placeholder_map
|
||||
skol_trait_predicate={:?}",
|
||||
skol_trait_predicate,
|
||||
);
|
||||
|
||||
let (def_id, substs) = match skol_trait_predicate.trait_ref.self_ty().sty {
|
||||
@ -1759,13 +1683,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
let matching_bound = util::elaborate_predicates(self.tcx(), bounds.predicates)
|
||||
.filter_to_traits()
|
||||
.find(|bound| {
|
||||
self.probe(|this, _| {
|
||||
this.match_projection(
|
||||
self.infcx.probe(|_| {
|
||||
self.match_projection(
|
||||
obligation,
|
||||
bound.clone(),
|
||||
skol_trait_predicate.trait_ref.clone(),
|
||||
&placeholder_map,
|
||||
snapshot,
|
||||
)
|
||||
})
|
||||
});
|
||||
@ -1783,12 +1705,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
obligation,
|
||||
bound,
|
||||
skol_trait_predicate.trait_ref.clone(),
|
||||
&placeholder_map,
|
||||
snapshot,
|
||||
);
|
||||
|
||||
self.infcx.pop_placeholders(placeholder_map, snapshot);
|
||||
|
||||
assert!(result);
|
||||
true
|
||||
}
|
||||
@ -1800,20 +1718,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
trait_bound: ty::PolyTraitRef<'tcx>,
|
||||
skol_trait_ref: ty::TraitRef<'tcx>,
|
||||
placeholder_map: &infer::PlaceholderMap<'tcx>,
|
||||
snapshot: &infer::CombinedSnapshot<'cx, 'tcx>,
|
||||
) -> bool {
|
||||
debug_assert!(!skol_trait_ref.has_escaping_bound_vars());
|
||||
if self.infcx
|
||||
self.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.sup(ty::Binder::dummy(skol_trait_ref), trait_bound)
|
||||
.is_err()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
self.infcx
|
||||
.leak_check(false, obligation.cause.span, placeholder_map, snapshot)
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
@ -1862,7 +1771,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
stack: &TraitObligationStack<'o, 'tcx>,
|
||||
where_clause_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
) -> Result<EvaluationResult, OverflowError> {
|
||||
self.probe(move |this, _| {
|
||||
self.evaluation_probe(|this| {
|
||||
match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) {
|
||||
Ok(obligations) => {
|
||||
this.evaluate_predicates_recursively(stack.list(), obligations.iter())
|
||||
@ -2015,14 +1924,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
obligation.predicate.def_id(),
|
||||
obligation.predicate.skip_binder().trait_ref.self_ty(),
|
||||
|impl_def_id| {
|
||||
self.probe(|this, snapshot| {
|
||||
if let Ok(placeholder_map) = this.match_impl(impl_def_id, obligation, snapshot)
|
||||
self.infcx.probe(|_| {
|
||||
if let Ok(_substs) = self.match_impl(impl_def_id, obligation)
|
||||
{
|
||||
candidates.vec.push(ImplCandidate(impl_def_id));
|
||||
|
||||
// N.B., we can safely drop the placeholder map
|
||||
// since we are in a probe.
|
||||
mem::drop(placeholder_map);
|
||||
}
|
||||
});
|
||||
},
|
||||
@ -2093,11 +1998,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
obligation.self_ty().skip_binder()
|
||||
);
|
||||
|
||||
self.probe(|this, _snapshot| {
|
||||
self.infcx.probe(|_snapshot| {
|
||||
// The code below doesn't care about regions, and the
|
||||
// self-ty here doesn't escape this probe, so just erase
|
||||
// any LBR.
|
||||
let self_ty = this.tcx().erase_late_bound_regions(&obligation.self_ty());
|
||||
let self_ty = self.tcx().erase_late_bound_regions(&obligation.self_ty());
|
||||
let poly_trait_ref = match self_ty.sty {
|
||||
ty::Dynamic(ref data, ..) => {
|
||||
if data.auto_traits()
|
||||
@ -2111,7 +2016,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
return;
|
||||
}
|
||||
|
||||
data.principal().with_self_ty(this.tcx(), self_ty)
|
||||
data.principal().with_self_ty(self.tcx(), self_ty)
|
||||
}
|
||||
ty::Infer(ty::TyVar(_)) => {
|
||||
debug!("assemble_candidates_from_object_ty: ambiguous");
|
||||
@ -2131,11 +2036,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
// correct trait, but also the correct type parameters.
|
||||
// For example, we may be trying to upcast `Foo` to `Bar<i32>`,
|
||||
// but `Foo` is declared as `trait Foo : Bar<u32>`.
|
||||
let upcast_trait_refs = util::supertraits(this.tcx(), poly_trait_ref)
|
||||
let upcast_trait_refs = util::supertraits(self.tcx(), poly_trait_ref)
|
||||
.filter(|upcast_trait_ref| {
|
||||
this.probe(|this, _| {
|
||||
self.infcx.probe(|_| {
|
||||
let upcast_trait_ref = upcast_trait_ref.clone();
|
||||
this.match_poly_trait_ref(obligation, upcast_trait_ref)
|
||||
self.match_poly_trait_ref(obligation, upcast_trait_ref)
|
||||
.is_ok()
|
||||
})
|
||||
})
|
||||
@ -2352,7 +2257,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
// See if we can toss out `victim` based on specialization.
|
||||
// This requires us to know *for sure* that the `other` impl applies
|
||||
// i.e., EvaluatedToOk:
|
||||
if other.evaluation == EvaluatedToOk {
|
||||
if other.evaluation.must_apply_modulo_regions() {
|
||||
match victim.candidate {
|
||||
ImplCandidate(victim_def) => {
|
||||
let tcx = self.tcx().global_tcx();
|
||||
@ -2379,7 +2284,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
ParamCandidate(ref cand) => {
|
||||
// Prefer these to a global where-clause bound
|
||||
// (see issue #50825)
|
||||
is_global(cand) && other.evaluation == EvaluatedToOk
|
||||
is_global(cand) && other.evaluation.must_apply_modulo_regions()
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
@ -2680,20 +2585,20 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
// binder moved -\
|
||||
let ty: ty::Binder<Ty<'tcx>> = ty::Binder::bind(ty); // <----/
|
||||
|
||||
self.in_snapshot(|this, snapshot| {
|
||||
let (skol_ty, placeholder_map) = this.infcx()
|
||||
self.infcx.in_snapshot(|_| {
|
||||
let (skol_ty, _) = self.infcx
|
||||
.replace_bound_vars_with_placeholders(&ty);
|
||||
let Normalized {
|
||||
value: normalized_ty,
|
||||
mut obligations,
|
||||
} = project::normalize_with_depth(
|
||||
this,
|
||||
self,
|
||||
param_env,
|
||||
cause.clone(),
|
||||
recursion_depth,
|
||||
&skol_ty,
|
||||
);
|
||||
let skol_obligation = this.tcx().predicate_for_trait_def(
|
||||
let skol_obligation = self.tcx().predicate_for_trait_def(
|
||||
param_env,
|
||||
cause.clone(),
|
||||
trait_def_id,
|
||||
@ -2702,8 +2607,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
&[],
|
||||
);
|
||||
obligations.push(skol_obligation);
|
||||
this.infcx()
|
||||
.plug_leaks(placeholder_map, snapshot, obligations)
|
||||
obligations
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
@ -2794,9 +2698,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) {
|
||||
self.in_snapshot(|this, snapshot| {
|
||||
self.infcx.in_snapshot(|_| {
|
||||
let result =
|
||||
this.match_projection_obligation_against_definition_bounds(obligation, snapshot);
|
||||
self.match_projection_obligation_against_definition_bounds(obligation);
|
||||
assert!(result);
|
||||
})
|
||||
}
|
||||
@ -2913,19 +2817,17 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
nested,
|
||||
);
|
||||
|
||||
let trait_obligations: Vec<PredicateObligation<'_>> = self.in_snapshot(|this, snapshot| {
|
||||
let trait_obligations: Vec<PredicateObligation<'_>> = self.infcx.in_snapshot(|_| {
|
||||
let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
|
||||
let (trait_ref, placeholder_map) = this.infcx()
|
||||
let (trait_ref, _) = self.infcx
|
||||
.replace_bound_vars_with_placeholders(&poly_trait_ref);
|
||||
let cause = obligation.derived_cause(ImplDerivedObligation);
|
||||
this.impl_or_trait_obligations(
|
||||
self.impl_or_trait_obligations(
|
||||
cause,
|
||||
obligation.recursion_depth + 1,
|
||||
obligation.param_env,
|
||||
trait_def_id,
|
||||
&trait_ref.substs,
|
||||
placeholder_map,
|
||||
snapshot,
|
||||
)
|
||||
});
|
||||
|
||||
@ -2950,18 +2852,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
|
||||
// First, create the substitutions by matching the impl again,
|
||||
// this time not in a probe.
|
||||
self.in_snapshot(|this, snapshot| {
|
||||
let (substs, placeholder_map) = this.rematch_impl(impl_def_id, obligation, snapshot);
|
||||
self.infcx.in_snapshot(|_| {
|
||||
let substs = self.rematch_impl(impl_def_id, obligation);
|
||||
debug!("confirm_impl_candidate: substs={:?}", substs);
|
||||
let cause = obligation.derived_cause(ImplDerivedObligation);
|
||||
this.vtable_impl(
|
||||
self.vtable_impl(
|
||||
impl_def_id,
|
||||
substs,
|
||||
cause,
|
||||
obligation.recursion_depth + 1,
|
||||
obligation.param_env,
|
||||
placeholder_map,
|
||||
snapshot,
|
||||
)
|
||||
})
|
||||
}
|
||||
@ -2973,12 +2873,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
cause: ObligationCause<'tcx>,
|
||||
recursion_depth: usize,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
placeholder_map: infer::PlaceholderMap<'tcx>,
|
||||
snapshot: &infer::CombinedSnapshot<'cx, 'tcx>,
|
||||
) -> VtableImplData<'tcx, PredicateObligation<'tcx>> {
|
||||
debug!(
|
||||
"vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={}, placeholder_map={:?})",
|
||||
impl_def_id, substs, recursion_depth, placeholder_map
|
||||
"vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={})",
|
||||
impl_def_id, substs, recursion_depth,
|
||||
);
|
||||
|
||||
let mut impl_obligations = self.impl_or_trait_obligations(
|
||||
@ -2987,8 +2885,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
param_env,
|
||||
impl_def_id,
|
||||
&substs.value,
|
||||
placeholder_map,
|
||||
snapshot,
|
||||
);
|
||||
|
||||
debug!(
|
||||
@ -3041,7 +2937,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
// reported an ambiguity. (When we do find a match, also
|
||||
// record it for later.)
|
||||
let nonmatching = util::supertraits(tcx, poly_trait_ref).take_while(
|
||||
|&t| match self.commit_if_ok(|this, _| this.match_poly_trait_ref(obligation, t)) {
|
||||
|&t| match self.infcx.commit_if_ok(|_| self.match_poly_trait_ref(obligation, t)) {
|
||||
Ok(obligations) => {
|
||||
upcast_trait_ref = Some(t);
|
||||
nested.extend(obligations);
|
||||
@ -3117,21 +3013,19 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
obligation, alias_def_id
|
||||
);
|
||||
|
||||
self.in_snapshot(|this, snapshot| {
|
||||
let (predicate, placeholder_map) = this.infcx()
|
||||
self.infcx.in_snapshot(|_| {
|
||||
let (predicate, _) = self.infcx()
|
||||
.replace_bound_vars_with_placeholders(&obligation.predicate);
|
||||
let trait_ref = predicate.trait_ref;
|
||||
let trait_def_id = trait_ref.def_id;
|
||||
let substs = trait_ref.substs;
|
||||
|
||||
let trait_obligations = this.impl_or_trait_obligations(
|
||||
let trait_obligations = self.impl_or_trait_obligations(
|
||||
obligation.cause.clone(),
|
||||
obligation.recursion_depth,
|
||||
obligation.param_env,
|
||||
trait_def_id,
|
||||
&substs,
|
||||
placeholder_map,
|
||||
snapshot,
|
||||
);
|
||||
|
||||
debug!(
|
||||
@ -3341,10 +3235,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
);
|
||||
tcx.mk_existential_predicates(iter)
|
||||
});
|
||||
let new_trait = tcx.mk_dynamic(existential_predicates, r_b);
|
||||
let source_trait = tcx.mk_dynamic(existential_predicates, r_b);
|
||||
let InferOk { obligations, .. } = self.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.eq(target, new_trait)
|
||||
.sup(target, source_trait)
|
||||
.map_err(|_| Unimplemented)?;
|
||||
nested.extend(obligations);
|
||||
|
||||
@ -3546,13 +3440,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
&mut self,
|
||||
impl_def_id: DefId,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
snapshot: &infer::CombinedSnapshot<'cx, 'tcx>,
|
||||
) -> (
|
||||
Normalized<'tcx, &'tcx Substs<'tcx>>,
|
||||
infer::PlaceholderMap<'tcx>,
|
||||
) {
|
||||
match self.match_impl(impl_def_id, obligation, snapshot) {
|
||||
Ok((substs, placeholder_map)) => (substs, placeholder_map),
|
||||
) -> Normalized<'tcx, &'tcx Substs<'tcx>> {
|
||||
match self.match_impl(impl_def_id, obligation) {
|
||||
Ok(substs) => substs,
|
||||
Err(()) => {
|
||||
bug!(
|
||||
"Impl {:?} was matchable against {:?} but now is not",
|
||||
@ -3567,14 +3457,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
&mut self,
|
||||
impl_def_id: DefId,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
snapshot: &infer::CombinedSnapshot<'cx, 'tcx>,
|
||||
) -> Result<
|
||||
(
|
||||
Normalized<'tcx, &'tcx Substs<'tcx>>,
|
||||
infer::PlaceholderMap<'tcx>,
|
||||
),
|
||||
(),
|
||||
> {
|
||||
) -> Result<Normalized<'tcx, &'tcx Substs<'tcx>>, ()> {
|
||||
let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
|
||||
|
||||
// Before we create the substitutions and everything, first
|
||||
@ -3584,7 +3467,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let (skol_obligation, placeholder_map) = self.infcx()
|
||||
let (skol_obligation, _) = self.infcx()
|
||||
.replace_bound_vars_with_placeholders(&obligation.predicate);
|
||||
let skol_obligation_trait_ref = skol_obligation.trait_ref;
|
||||
|
||||
@ -3616,22 +3499,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
.map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?;
|
||||
nested_obligations.extend(obligations);
|
||||
|
||||
if let Err(e) =
|
||||
self.infcx
|
||||
.leak_check(false, obligation.cause.span, &placeholder_map, snapshot)
|
||||
{
|
||||
debug!("match_impl: failed leak check due to `{}`", e);
|
||||
return Err(());
|
||||
}
|
||||
|
||||
debug!("match_impl: success impl_substs={:?}", impl_substs);
|
||||
Ok((
|
||||
Normalized {
|
||||
value: impl_substs,
|
||||
obligations: nested_obligations,
|
||||
},
|
||||
placeholder_map,
|
||||
))
|
||||
Ok(Normalized {
|
||||
value: impl_substs,
|
||||
obligations: nested_obligations,
|
||||
})
|
||||
}
|
||||
|
||||
fn fast_reject_trait_refs(
|
||||
@ -3787,8 +3659,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
def_id: DefId, // of impl or trait
|
||||
substs: &Substs<'tcx>, // for impl or trait
|
||||
placeholder_map: infer::PlaceholderMap<'tcx>,
|
||||
snapshot: &infer::CombinedSnapshot<'cx, 'tcx>,
|
||||
) -> Vec<PredicateObligation<'tcx>> {
|
||||
debug!("impl_or_trait_obligations(def_id={:?})", def_id);
|
||||
let tcx = self.tcx();
|
||||
@ -3850,8 +3720,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
let mut seen = FxHashSet::default();
|
||||
predicates.retain(|i| seen.insert(i.clone()));
|
||||
}
|
||||
self.infcx()
|
||||
.plug_leaks(placeholder_map, snapshot, predicates)
|
||||
|
||||
predicates
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ use hir::def_id::DefId;
|
||||
use infer::{InferCtxt, InferOk};
|
||||
use lint;
|
||||
use traits::{self, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine};
|
||||
use traits::coherence;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use syntax_pos::DUMMY_SP;
|
||||
@ -32,6 +33,7 @@ pub struct OverlapError {
|
||||
pub trait_desc: String,
|
||||
pub self_desc: Option<String>,
|
||||
pub intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>,
|
||||
pub involves_placeholder: bool,
|
||||
}
|
||||
|
||||
/// Given a subst for the requested impl, translate it to a subst
|
||||
@ -370,6 +372,10 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>(
|
||||
cause.add_intercrate_ambiguity_hint(&mut err);
|
||||
}
|
||||
|
||||
if overlap.involves_placeholder {
|
||||
coherence::add_placeholder_note(&mut err);
|
||||
}
|
||||
|
||||
err.emit();
|
||||
}
|
||||
} else {
|
||||
|
@ -164,6 +164,7 @@ impl<'a, 'gcx, 'tcx> Children {
|
||||
None
|
||||
},
|
||||
intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes,
|
||||
involves_placeholder: overlap.involves_placeholder,
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use hir::def_id::DefId;
|
||||
use ty::{self, BoundRegion, Region, Ty, TyCtxt};
|
||||
use ty::{self, Region, Ty, TyCtxt};
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use rustc_target::spec::abi;
|
||||
@ -9,7 +9,7 @@ use syntax_pos::Span;
|
||||
|
||||
use hir;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct ExpectedFound<T> {
|
||||
pub expected: T,
|
||||
pub found: T,
|
||||
@ -27,8 +27,7 @@ pub enum TypeError<'tcx> {
|
||||
ArgCount,
|
||||
|
||||
RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>),
|
||||
RegionsInsufficientlyPolymorphic(BoundRegion, Region<'tcx>),
|
||||
RegionsOverlyPolymorphic(BoundRegion, Region<'tcx>),
|
||||
RegionsPlaceholderMismatch,
|
||||
|
||||
Sorts(ExpectedFound<Ty<'tcx>>),
|
||||
IntMismatch(ExpectedFound<ty::IntVarValue>),
|
||||
@ -102,17 +101,8 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
|
||||
RegionsDoesNotOutlive(..) => {
|
||||
write!(f, "lifetime mismatch")
|
||||
}
|
||||
RegionsInsufficientlyPolymorphic(br, _) => {
|
||||
write!(f,
|
||||
"expected bound lifetime parameter{}{}, found concrete lifetime",
|
||||
if br.is_named() { " " } else { "" },
|
||||
br)
|
||||
}
|
||||
RegionsOverlyPolymorphic(br, _) => {
|
||||
write!(f,
|
||||
"expected concrete lifetime, found bound lifetime parameter{}{}",
|
||||
if br.is_named() { " " } else { "" },
|
||||
br)
|
||||
RegionsPlaceholderMismatch => {
|
||||
write!(f, "one type is more general than the other")
|
||||
}
|
||||
Sorts(values) => ty::tls::with(|tcx| {
|
||||
report_maybe_different(f, &values.expected.sort_string(tcx),
|
||||
|
@ -382,7 +382,7 @@ define_queries! { <'tcx>
|
||||
/// might want to use `reveal_all()` method to change modes.
|
||||
[] fn param_env: ParamEnv(DefId) -> ty::ParamEnv<'tcx>,
|
||||
|
||||
/// Trait selection queries. These are best used by invoking `ty.moves_by_default()`,
|
||||
/// Trait selection queries. These are best used by invoking `ty.is_copy_modulo_regions()`,
|
||||
/// `ty.is_copy()`, etc, since that will prune the environment where possible.
|
||||
[] fn is_copy_raw: is_copy_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
|
||||
[] fn is_sized_raw: is_sized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
|
||||
|
@ -434,12 +434,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
|
||||
RegionsDoesNotOutlive(a, b) => {
|
||||
return tcx.lift(&(a, b)).map(|(a, b)| RegionsDoesNotOutlive(a, b))
|
||||
}
|
||||
RegionsInsufficientlyPolymorphic(a, b) => {
|
||||
return tcx.lift(&b).map(|b| RegionsInsufficientlyPolymorphic(a, b))
|
||||
}
|
||||
RegionsOverlyPolymorphic(a, b) => {
|
||||
return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b))
|
||||
}
|
||||
RegionsPlaceholderMismatch => RegionsPlaceholderMismatch,
|
||||
IntMismatch(x) => IntMismatch(x),
|
||||
FloatMismatch(x) => FloatMismatch(x),
|
||||
Traits(x) => Traits(x),
|
||||
@ -1006,8 +1001,7 @@ EnumTypeFoldableImpl! {
|
||||
(ty::error::TypeError::FixedArraySize)(x),
|
||||
(ty::error::TypeError::ArgCount),
|
||||
(ty::error::TypeError::RegionsDoesNotOutlive)(a, b),
|
||||
(ty::error::TypeError::RegionsInsufficientlyPolymorphic)(a, b),
|
||||
(ty::error::TypeError::RegionsOverlyPolymorphic)(a, b),
|
||||
(ty::error::TypeError::RegionsPlaceholderMismatch),
|
||||
(ty::error::TypeError::IntMismatch)(x),
|
||||
(ty::error::TypeError::FloatMismatch)(x),
|
||||
(ty::error::TypeError::Traits)(x),
|
||||
|
@ -1396,6 +1396,13 @@ impl RegionKind {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_placeholder(&self) -> bool {
|
||||
match *self {
|
||||
ty::RePlaceholder(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bound_at_or_above_binder(&self, index: DebruijnIndex) -> bool {
|
||||
match *self {
|
||||
ty::ReLateBound(debruijn, _) => debruijn >= index,
|
||||
|
@ -203,7 +203,7 @@ impl<'tcx> ty::ParamEnv<'tcx> {
|
||||
let cause = ObligationCause { span, ..ObligationCause::dummy() };
|
||||
let ctx = traits::FulfillmentContext::new();
|
||||
match traits::fully_normalize(&infcx, ctx, cause, self, &ty) {
|
||||
Ok(ty) => if infcx.type_moves_by_default(self, ty, span) {
|
||||
Ok(ty) => if !infcx.type_is_copy_modulo_regions(self, ty, span) {
|
||||
infringing.push(field);
|
||||
}
|
||||
Err(errors) => {
|
||||
@ -621,14 +621,27 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> ty::TyS<'tcx> {
|
||||
pub fn moves_by_default(&'tcx self,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
span: Span)
|
||||
-> bool {
|
||||
!tcx.at(span).is_copy_raw(param_env.and(self))
|
||||
/// Checks whether values of this type `T` are *moved* or *copied*
|
||||
/// when referenced -- this amounts to a check for whether `T:
|
||||
/// Copy`, but note that we **don't** consider lifetimes when
|
||||
/// doing this check. This means that we may generate MIR which
|
||||
/// does copies even when the type actually doesn't satisfy the
|
||||
/// full requirements for the `Copy` trait (cc #29149) -- this
|
||||
/// winds up being reported as an error during NLL borrow check.
|
||||
pub fn is_copy_modulo_regions(&'tcx self,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
span: Span)
|
||||
-> bool {
|
||||
tcx.at(span).is_copy_raw(param_env.and(self))
|
||||
}
|
||||
|
||||
/// Checks whether values of this type `T` have a size known at
|
||||
/// compile time (i.e., whether `T: Sized`). Lifetimes are ignored
|
||||
/// for the purposes of this check, so it can be an
|
||||
/// over-approximation in generic contexts, where one can have
|
||||
/// strange rules like `<T as Foo<'static>>::Bar: Sized` that
|
||||
/// actually carry lifetime requirements.
|
||||
pub fn is_sized(&'tcx self,
|
||||
tcx_at: TyCtxtAt<'a, 'tcx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>)-> bool
|
||||
@ -636,6 +649,13 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
|
||||
tcx_at.is_sized_raw(param_env.and(self))
|
||||
}
|
||||
|
||||
/// Checks whether values of this type `T` implement the `Freeze`
|
||||
/// trait -- frozen types are those that do not contain a
|
||||
/// `UnsafeCell` anywhere. This is a language concept used to
|
||||
/// distinguish "true immutability", which is relevant to
|
||||
/// optimization as well as the rules around static values. Note
|
||||
/// that the `Freeze` trait is not exposed to end users and is
|
||||
/// effectively an implementation detail.
|
||||
pub fn is_freeze(&'tcx self,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
@ -851,11 +871,13 @@ fn is_copy_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
let (param_env, ty) = query.into_parts();
|
||||
let trait_def_id = tcx.require_lang_item(lang_items::CopyTraitLangItem);
|
||||
tcx.infer_ctxt()
|
||||
.enter(|infcx| traits::type_known_to_meet_bound(&infcx,
|
||||
param_env,
|
||||
ty,
|
||||
trait_def_id,
|
||||
DUMMY_SP))
|
||||
.enter(|infcx| traits::type_known_to_meet_bound_modulo_regions(
|
||||
&infcx,
|
||||
param_env,
|
||||
ty,
|
||||
trait_def_id,
|
||||
DUMMY_SP,
|
||||
))
|
||||
}
|
||||
|
||||
fn is_sized_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
@ -865,11 +887,13 @@ fn is_sized_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
let (param_env, ty) = query.into_parts();
|
||||
let trait_def_id = tcx.require_lang_item(lang_items::SizedTraitLangItem);
|
||||
tcx.infer_ctxt()
|
||||
.enter(|infcx| traits::type_known_to_meet_bound(&infcx,
|
||||
param_env,
|
||||
ty,
|
||||
trait_def_id,
|
||||
DUMMY_SP))
|
||||
.enter(|infcx| traits::type_known_to_meet_bound_modulo_regions(
|
||||
&infcx,
|
||||
param_env,
|
||||
ty,
|
||||
trait_def_id,
|
||||
DUMMY_SP,
|
||||
))
|
||||
}
|
||||
|
||||
fn is_freeze_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
@ -879,11 +903,13 @@ fn is_freeze_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
let (param_env, ty) = query.into_parts();
|
||||
let trait_def_id = tcx.require_lang_item(lang_items::FreezeTraitLangItem);
|
||||
tcx.infer_ctxt()
|
||||
.enter(|infcx| traits::type_known_to_meet_bound(&infcx,
|
||||
param_env,
|
||||
ty,
|
||||
trait_def_id,
|
||||
DUMMY_SP))
|
||||
.enter(|infcx| traits::type_known_to_meet_bound_modulo_regions(
|
||||
&infcx,
|
||||
param_env,
|
||||
ty,
|
||||
trait_def_id,
|
||||
DUMMY_SP,
|
||||
))
|
||||
}
|
||||
|
||||
fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
@ -921,11 +947,11 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
// `ManuallyDrop` doesn't have a destructor regardless of field types.
|
||||
ty::Adt(def, _) if Some(def.did) == tcx.lang_items().manually_drop() => false,
|
||||
|
||||
// Issue #22536: We first query type_moves_by_default. It sees a
|
||||
// Issue #22536: We first query `is_copy_modulo_regions`. It sees a
|
||||
// normalized version of the type, and therefore will definitely
|
||||
// know whether the type implements Copy (and thus needs no
|
||||
// cleanup/drop/zeroing) ...
|
||||
_ if !ty.moves_by_default(tcx, param_env, DUMMY_SP) => false,
|
||||
_ if ty.is_copy_modulo_regions(tcx, param_env, DUMMY_SP) => false,
|
||||
|
||||
// ... (issue #22536 continued) but as an optimization, still use
|
||||
// prior logic of asking for the structural "may drop".
|
||||
|
@ -9,7 +9,7 @@ use ty::{Error, Str, Array, Slice, Float, FnDef, FnPtr};
|
||||
use ty::{Param, Bound, RawPtr, Ref, Never, Tuple};
|
||||
use ty::{Closure, Generator, GeneratorWitness, Foreign, Projection, Opaque};
|
||||
use ty::{Placeholder, UnnormalizedProjection, Dynamic, Int, Uint, Infer};
|
||||
use ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind};
|
||||
use ty::{self, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind};
|
||||
use util::nodemap::FxHashSet;
|
||||
|
||||
use std::cell::Cell;
|
||||
@ -21,17 +21,163 @@ use syntax::ast::CRATE_NODE_ID;
|
||||
use syntax::symbol::{Symbol, InternedString};
|
||||
use hir;
|
||||
|
||||
thread_local! {
|
||||
/// Mechanism for highlighting of specific regions for display in NLL region inference errors.
|
||||
/// Contains region to highlight and counter for number to use when highlighting.
|
||||
static HIGHLIGHT_REGION_FOR_REGIONVID: Cell<Option<(RegionVid, usize)>> = Cell::new(None)
|
||||
/// The "region highlights" are used to control region printing during
|
||||
/// specific error messages. When a "region highlight" is enabled, it
|
||||
/// gives an alternate way to print specific regions. For now, we
|
||||
/// always print those regions using a number, so something like `'0`.
|
||||
///
|
||||
/// Regions not selected by the region highlight mode are presently
|
||||
/// unaffected.
|
||||
#[derive(Copy, Clone, Default)]
|
||||
pub struct RegionHighlightMode {
|
||||
/// If enabled, when we see the selected region, use `"'N"`
|
||||
/// instead of the ordinary behavior.
|
||||
highlight_regions: [Option<(ty::RegionKind, usize)>; 3],
|
||||
|
||||
/// If enabled, when printing a "free region" that originated from
|
||||
/// the given `ty::BoundRegion`, print it as `'1`. Free regions that would ordinarily
|
||||
/// have names print as normal.
|
||||
///
|
||||
/// This is used when you have a signature like `fn foo(x: &u32,
|
||||
/// y: &'a u32)` and we want to give a name to the region of the
|
||||
/// reference `x`.
|
||||
highlight_bound_region: Option<(ty::BoundRegion, usize)>,
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
/// Mechanism for highlighting of specific regions for display in NLL's 'borrow does not live
|
||||
/// long enough' errors. Contains a region to highlight and a counter to use.
|
||||
static HIGHLIGHT_REGION_FOR_BOUND_REGION: Cell<Option<(ty::BoundRegion, usize)>> =
|
||||
Cell::new(None)
|
||||
/// Mechanism for highlighting of specific regions for display in NLL region inference errors.
|
||||
/// Contains region to highlight and counter for number to use when highlighting.
|
||||
static REGION_HIGHLIGHT_MODE: Cell<RegionHighlightMode> =
|
||||
Cell::new(RegionHighlightMode::default())
|
||||
}
|
||||
|
||||
impl RegionHighlightMode {
|
||||
/// Read and return current region highlight settings (accesses thread-local state).a
|
||||
pub fn get() -> Self {
|
||||
REGION_HIGHLIGHT_MODE.with(|c| c.get())
|
||||
}
|
||||
|
||||
/// Internal helper to update current settings during the execution of `op`.
|
||||
fn set<R>(
|
||||
old_mode: Self,
|
||||
new_mode: Self,
|
||||
op: impl FnOnce() -> R,
|
||||
) -> R {
|
||||
REGION_HIGHLIGHT_MODE.with(|c| {
|
||||
c.set(new_mode);
|
||||
let result = op();
|
||||
c.set(old_mode);
|
||||
result
|
||||
})
|
||||
}
|
||||
|
||||
/// If `region` and `number` are both `Some`, invoke
|
||||
/// `highlighting_region`. Otherwise, just invoke `op` directly.
|
||||
pub fn maybe_highlighting_region<R>(
|
||||
region: Option<ty::Region<'_>>,
|
||||
number: Option<usize>,
|
||||
op: impl FnOnce() -> R,
|
||||
) -> R {
|
||||
if let Some(k) = region {
|
||||
if let Some(n) = number {
|
||||
return Self::highlighting_region(k, n, op);
|
||||
}
|
||||
}
|
||||
|
||||
op()
|
||||
}
|
||||
|
||||
/// During the execution of `op`, highlight the region inference
|
||||
/// vairable `vid` as `'N`. We can only highlight one region vid
|
||||
/// at a time.
|
||||
pub fn highlighting_region<R>(
|
||||
region: ty::Region<'_>,
|
||||
number: usize,
|
||||
op: impl FnOnce() -> R,
|
||||
) -> R {
|
||||
let old_mode = Self::get();
|
||||
let mut new_mode = old_mode;
|
||||
let first_avail_slot = new_mode.highlight_regions.iter_mut()
|
||||
.filter(|s| s.is_none())
|
||||
.next()
|
||||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
"can only highlight {} placeholders at a time",
|
||||
old_mode.highlight_regions.len(),
|
||||
)
|
||||
});
|
||||
*first_avail_slot = Some((*region, number));
|
||||
Self::set(old_mode, new_mode, op)
|
||||
}
|
||||
|
||||
/// Convenience wrapper for `highlighting_region`
|
||||
pub fn highlighting_region_vid<R>(
|
||||
vid: ty::RegionVid,
|
||||
number: usize,
|
||||
op: impl FnOnce() -> R,
|
||||
) -> R {
|
||||
Self::highlighting_region(&ty::ReVar(vid), number, op)
|
||||
}
|
||||
|
||||
/// Returns true if any placeholders are highlighted.
|
||||
fn any_region_vids_highlighted(&self) -> bool {
|
||||
Self::get()
|
||||
.highlight_regions
|
||||
.iter()
|
||||
.any(|h| match h {
|
||||
Some((ty::ReVar(_), _)) => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns `Some(n)` with the number to use for the given region,
|
||||
/// if any.
|
||||
fn region_highlighted(&self, region: ty::Region<'_>) -> Option<usize> {
|
||||
Self::get()
|
||||
.highlight_regions
|
||||
.iter()
|
||||
.filter_map(|h| match h {
|
||||
Some((r, n)) if r == region => Some(*n),
|
||||
_ => None,
|
||||
})
|
||||
.next()
|
||||
}
|
||||
|
||||
/// During the execution of `op`, highlight the given bound
|
||||
/// region. We can only highlight one bound region at a time. See
|
||||
/// the field `highlight_bound_region` for more detailed notes.
|
||||
pub fn highlighting_bound_region<R>(
|
||||
br: ty::BoundRegion,
|
||||
number: usize,
|
||||
op: impl FnOnce() -> R,
|
||||
) -> R {
|
||||
let old_mode = Self::get();
|
||||
assert!(old_mode.highlight_bound_region.is_none());
|
||||
Self::set(
|
||||
old_mode,
|
||||
Self {
|
||||
highlight_bound_region: Some((br, number)),
|
||||
..old_mode
|
||||
},
|
||||
op,
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns true if any placeholders are highlighted.
|
||||
pub fn any_placeholders_highlighted(&self) -> bool {
|
||||
Self::get()
|
||||
.highlight_regions
|
||||
.iter()
|
||||
.any(|h| match h {
|
||||
Some((ty::RePlaceholder(_), _)) => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns `Some(N)` if the placeholder `p` is highlighted to print as `'N`.
|
||||
pub fn placeholder_highlight(&self, p: ty::PlaceholderRegion) -> Option<usize> {
|
||||
self.region_highlighted(&ty::RePlaceholder(p))
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! gen_display_debug_body {
|
||||
@ -553,42 +699,6 @@ pub fn parameterized<F: fmt::Write>(f: &mut F,
|
||||
PrintContext::new().parameterized(f, substs, did, projections)
|
||||
}
|
||||
|
||||
fn get_highlight_region_for_regionvid() -> Option<(RegionVid, usize)> {
|
||||
HIGHLIGHT_REGION_FOR_REGIONVID.with(|hr| hr.get())
|
||||
}
|
||||
|
||||
pub fn with_highlight_region_for_regionvid<R>(
|
||||
r: RegionVid,
|
||||
counter: usize,
|
||||
op: impl FnOnce() -> R
|
||||
) -> R {
|
||||
HIGHLIGHT_REGION_FOR_REGIONVID.with(|hr| {
|
||||
assert_eq!(hr.get(), None);
|
||||
hr.set(Some((r, counter)));
|
||||
let r = op();
|
||||
hr.set(None);
|
||||
r
|
||||
})
|
||||
}
|
||||
|
||||
fn get_highlight_region_for_bound_region() -> Option<(ty::BoundRegion, usize)> {
|
||||
HIGHLIGHT_REGION_FOR_BOUND_REGION.with(|hr| hr.get())
|
||||
}
|
||||
|
||||
pub fn with_highlight_region_for_bound_region<R>(
|
||||
r: ty::BoundRegion,
|
||||
counter: usize,
|
||||
op: impl Fn() -> R
|
||||
) -> R {
|
||||
HIGHLIGHT_REGION_FOR_BOUND_REGION.with(|hr| {
|
||||
assert_eq!(hr.get(), None);
|
||||
hr.set(Some((r, counter)));
|
||||
let r = op();
|
||||
hr.set(None);
|
||||
r
|
||||
})
|
||||
}
|
||||
|
||||
impl<'a, T: Print> Print for &'a T {
|
||||
fn print<F: fmt::Write>(&self, f: &mut F, cx: &mut PrintContext) -> fmt::Result {
|
||||
(*self).print(f, cx)
|
||||
@ -740,7 +850,7 @@ define_print! {
|
||||
return self.print_debug(f, cx);
|
||||
}
|
||||
|
||||
if let Some((region, counter)) = get_highlight_region_for_bound_region() {
|
||||
if let Some((region, counter)) = RegionHighlightMode::get().highlight_bound_region {
|
||||
if *self == region {
|
||||
return match *self {
|
||||
BrNamed(_, name) => write!(f, "{}", name),
|
||||
@ -768,13 +878,37 @@ define_print! {
|
||||
}
|
||||
}
|
||||
|
||||
define_print! {
|
||||
() ty::PlaceholderRegion, (self, f, cx) {
|
||||
display {
|
||||
if cx.is_verbose {
|
||||
return self.print_debug(f, cx);
|
||||
}
|
||||
|
||||
let highlight = RegionHighlightMode::get();
|
||||
if let Some(counter) = highlight.placeholder_highlight(*self) {
|
||||
write!(f, "'{}", counter)
|
||||
} else if highlight.any_placeholders_highlighted() {
|
||||
write!(f, "'_")
|
||||
} else {
|
||||
write!(f, "{}", self.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
define_print! {
|
||||
() ty::RegionKind, (self, f, cx) {
|
||||
display {
|
||||
if cx.is_verbose || get_highlight_region_for_regionvid().is_some() {
|
||||
if cx.is_verbose {
|
||||
return self.print_debug(f, cx);
|
||||
}
|
||||
|
||||
// Watch out for region highlights.
|
||||
if let Some(n) = RegionHighlightMode::get().region_highlighted(self) {
|
||||
return write!(f, "'{:?}", n);
|
||||
}
|
||||
|
||||
// These printouts are concise. They do not contain all the information
|
||||
// the user might want to diagnose an error, but there is basically no way
|
||||
// to fit that into a short string. Hence the recommendation to use
|
||||
@ -784,10 +918,12 @@ define_print! {
|
||||
write!(f, "{}", data.name)
|
||||
}
|
||||
ty::ReLateBound(_, br) |
|
||||
ty::ReFree(ty::FreeRegion { bound_region: br, .. }) |
|
||||
ty::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => {
|
||||
ty::ReFree(ty::FreeRegion { bound_region: br, .. }) => {
|
||||
write!(f, "{}", br)
|
||||
}
|
||||
ty::RePlaceholder(p) => {
|
||||
write!(f, "{}", p)
|
||||
}
|
||||
ty::ReScope(scope) if cx.identify_regions => {
|
||||
match scope.data {
|
||||
region::ScopeData::Node =>
|
||||
@ -806,11 +942,16 @@ define_print! {
|
||||
),
|
||||
}
|
||||
}
|
||||
ty::ReVar(region_vid) if cx.identify_regions => {
|
||||
write!(f, "'{}rv", region_vid.index())
|
||||
ty::ReVar(region_vid) => {
|
||||
if RegionHighlightMode::get().any_region_vids_highlighted() {
|
||||
write!(f, "{:?}", region_vid)
|
||||
} else if cx.identify_regions {
|
||||
write!(f, "'{}rv", region_vid.index())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
ty::ReScope(_) |
|
||||
ty::ReVar(_) |
|
||||
ty::ReErased => Ok(()),
|
||||
ty::ReStatic => write!(f, "'static"),
|
||||
ty::ReEmpty => write!(f, "'<empty>"),
|
||||
@ -939,13 +1080,10 @@ impl fmt::Debug for ty::FloatVid {
|
||||
|
||||
impl fmt::Debug for ty::RegionVid {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if let Some((region, counter)) = get_highlight_region_for_regionvid() {
|
||||
debug!("RegionVid.fmt: region={:?} self={:?} counter={:?}", region, self, counter);
|
||||
return if *self == region {
|
||||
write!(f, "'{:?}", counter)
|
||||
} else {
|
||||
write!(f, "'_")
|
||||
}
|
||||
if let Some(counter) = RegionHighlightMode::get().region_highlighted(&ty::ReVar(*self)) {
|
||||
return write!(f, "'{:?}", counter);
|
||||
} else if RegionHighlightMode::get().any_region_vids_highlighted() {
|
||||
return write!(f, "'_");
|
||||
}
|
||||
|
||||
write!(f, "'_#{}r", self.index())
|
||||
|
@ -7,7 +7,6 @@ use errors::{DiagnosticBuilder, Level};
|
||||
use rustc::hir;
|
||||
use rustc::hir::map as hir_map;
|
||||
use rustc::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc::infer::type_variable::TypeVariableOrigin;
|
||||
use rustc::infer::{self, InferOk, InferResult, SuppressRegionErrors};
|
||||
use rustc::middle::region;
|
||||
use rustc::session::config::{OutputFilenames, OutputTypes};
|
||||
@ -26,7 +25,6 @@ use syntax::ast;
|
||||
use syntax::feature_gate::UnstableFeatures;
|
||||
use syntax::source_map::{FileName, FilePathMapping, SourceMap};
|
||||
use syntax::symbol::Symbol;
|
||||
use syntax_pos::DUMMY_SP;
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::sync::mpsc;
|
||||
@ -431,17 +429,6 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks that `t1 <: t2` is false (this may register additional
|
||||
/// region checks).
|
||||
pub fn check_not_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) {
|
||||
match self.sub(t1, t2) {
|
||||
Err(_) => {}
|
||||
Ok(_) => {
|
||||
panic!("unexpected success computing sub({:?},{:?})", t1, t2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -470,25 +457,6 @@ fn contravariant_region_ptr_err() {
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_free_bound_false() {
|
||||
//! Test that:
|
||||
//!
|
||||
//! fn(&'a isize) <: for<'b> fn(&'b isize)
|
||||
//!
|
||||
//! *does not* hold.
|
||||
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
|
||||
env.create_simple_region_hierarchy();
|
||||
let t_rptr_free1 = env.t_rptr_free(1);
|
||||
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
||||
env.check_not_sub(
|
||||
env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_bound_free_true() {
|
||||
//! Test that:
|
||||
@ -508,25 +476,6 @@ fn sub_bound_free_true() {
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_free_bound_false_infer() {
|
||||
//! Test that:
|
||||
//!
|
||||
//! fn(_#1) <: for<'b> fn(&'b isize)
|
||||
//!
|
||||
//! does NOT hold for any instantiation of `_#1`.
|
||||
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
||||
let t_infer1 = env.infcx
|
||||
.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP));
|
||||
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
||||
env.check_not_sub(
|
||||
env.t_fn(&[t_infer1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
/// Test substituting a bound region into a function, which introduces another level of binding.
|
||||
/// This requires adjusting the Debruijn index.
|
||||
#[test]
|
||||
|
@ -540,7 +540,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations {
|
||||
return;
|
||||
}
|
||||
let param_env = ty::ParamEnv::empty();
|
||||
if !ty.moves_by_default(cx.tcx, param_env, item.span) {
|
||||
if ty.is_copy_modulo_regions(cx.tcx, param_env, item.span) {
|
||||
return;
|
||||
}
|
||||
if param_env.can_type_implement_copy(cx.tcx, ty).is_ok() {
|
||||
|
@ -12,7 +12,7 @@ use rustc::mir::{
|
||||
TerminatorKind, VarBindingForm,
|
||||
};
|
||||
use rustc::ty::{self, DefIdTree};
|
||||
use rustc::util::ppaux::with_highlight_region_for_bound_region;
|
||||
use rustc::util::ppaux::RegionHighlightMode;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
@ -2177,7 +2177,7 @@ impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
|
||||
ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }),
|
||||
_,
|
||||
_,
|
||||
) => with_highlight_region_for_bound_region(*br, counter, || ty.to_string()),
|
||||
) => RegionHighlightMode::highlighting_bound_region(*br, counter, || ty.to_string()),
|
||||
_ => ty.to_string(),
|
||||
}
|
||||
}
|
||||
@ -2189,7 +2189,11 @@ impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
|
||||
ty::TyKind::Ref(region, _, _) => match region {
|
||||
ty::RegionKind::ReLateBound(_, br)
|
||||
| ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => {
|
||||
with_highlight_region_for_bound_region(*br, counter, || region.to_string())
|
||||
RegionHighlightMode::highlighting_bound_region(
|
||||
*br,
|
||||
counter,
|
||||
|| region.to_string(),
|
||||
)
|
||||
}
|
||||
_ => region.to_string(),
|
||||
},
|
||||
|
@ -8,7 +8,7 @@ use rustc::infer::InferCtxt;
|
||||
use rustc::mir::Mir;
|
||||
use rustc::ty::subst::{Substs, UnpackedKind};
|
||||
use rustc::ty::{self, RegionKind, RegionVid, Ty, TyCtxt};
|
||||
use rustc::util::ppaux::with_highlight_region_for_regionvid;
|
||||
use rustc::util::ppaux::RegionHighlightMode;
|
||||
use rustc_errors::DiagnosticBuilder;
|
||||
use syntax::ast::{Name, DUMMY_NODE_ID};
|
||||
use syntax::symbol::keywords;
|
||||
@ -396,7 +396,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
argument_ty: Ty<'tcx>,
|
||||
counter: &mut usize,
|
||||
) -> Option<RegionName> {
|
||||
let type_name = with_highlight_region_for_regionvid(needle_fr, *counter, || {
|
||||
let type_name = RegionHighlightMode::highlighting_region_vid(needle_fr, *counter, || {
|
||||
infcx.extract_type_name(&argument_ty)
|
||||
});
|
||||
|
||||
@ -673,8 +673,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
return None;
|
||||
}
|
||||
|
||||
let type_name = with_highlight_region_for_regionvid(
|
||||
fr, *counter, || infcx.extract_type_name(&return_ty));
|
||||
let type_name = RegionHighlightMode::highlighting_region_vid(
|
||||
fr, *counter, || infcx.extract_type_name(&return_ty),
|
||||
);
|
||||
|
||||
let mir_node_id = tcx.hir().as_local_node_id(mir_def_id).expect("non-local mir");
|
||||
|
||||
|
@ -503,13 +503,17 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
||||
substs: tcx.mk_substs_trait(place_ty.to_ty(tcx), &[]),
|
||||
};
|
||||
|
||||
// In order to have a Copy operand, the type T of the value must be Copy. Note that we
|
||||
// prove that T: Copy, rather than using the type_moves_by_default test. This is
|
||||
// important because type_moves_by_default ignores the resulting region obligations and
|
||||
// assumes they pass. This can result in bounds from Copy impls being unsoundly ignored
|
||||
// (e.g., #29149). Note that we decide to use Copy before knowing whether the bounds
|
||||
// fully apply: in effect, the rule is that if a value of some type could implement
|
||||
// Copy, then it must.
|
||||
// In order to have a Copy operand, the type T of the
|
||||
// value must be Copy. Note that we prove that T: Copy,
|
||||
// rather than using the `is_copy_modulo_regions`
|
||||
// test. This is important because
|
||||
// `is_copy_modulo_regions` ignores the resulting region
|
||||
// obligations and assumes they pass. This can result in
|
||||
// bounds from Copy impls being unsoundly ignored (e.g.,
|
||||
// #29149). Note that we decide to use Copy before knowing
|
||||
// whether the bounds fully apply: in effect, the rule is
|
||||
// that if a value of some type could implement Copy, then
|
||||
// it must.
|
||||
self.cx.prove_trait_ref(
|
||||
trait_ref,
|
||||
location.to_locations(),
|
||||
|
@ -71,7 +71,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
pub fn consume_by_copy_or_move(&self, place: Place<'tcx>) -> Operand<'tcx> {
|
||||
let tcx = self.hir.tcx();
|
||||
let ty = place.ty(&self.local_decls, tcx).to_ty(tcx);
|
||||
if self.hir.type_moves_by_default(ty, DUMMY_SP) {
|
||||
if !self.hir.type_is_copy_modulo_regions(ty, DUMMY_SP) {
|
||||
Operand::Move(place)
|
||||
} else {
|
||||
Operand::Copy(place)
|
||||
|
@ -223,8 +223,8 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
||||
self.check_overflow
|
||||
}
|
||||
|
||||
pub fn type_moves_by_default(&self, ty: Ty<'tcx>, span: Span) -> bool {
|
||||
self.infcx.type_moves_by_default(self.param_env, ty, span)
|
||||
pub fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool {
|
||||
self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -545,7 +545,7 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
|
||||
match bm {
|
||||
ty::BindByValue(..) => {
|
||||
let pat_ty = cx.tables.node_id_to_type(p.hir_id);
|
||||
if pat_ty.moves_by_default(cx.tcx, cx.param_env, pat.span) {
|
||||
if !pat_ty.is_copy_modulo_regions(cx.tcx, cx.param_env, pat.span) {
|
||||
check_move(p, sub.as_ref().map(|p| &**p), span_vec);
|
||||
}
|
||||
}
|
||||
|
@ -310,7 +310,7 @@ fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
debug!("build_clone_shim(def_id={:?})", def_id);
|
||||
|
||||
let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty);
|
||||
let is_copy = !self_ty.moves_by_default(tcx, tcx.param_env(def_id), builder.span);
|
||||
let is_copy = self_ty.is_copy_modulo_regions(tcx, tcx.param_env(def_id), builder.span);
|
||||
|
||||
let dest = Place::Local(RETURN_PLACE);
|
||||
let src = Place::Local(Local::new(1+0)).deref();
|
||||
|
@ -224,8 +224,11 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
|
||||
"non-field projection {:?} from union?",
|
||||
place)
|
||||
};
|
||||
if elem_ty.moves_by_default(self.tcx, self.param_env,
|
||||
self.source_info.span) {
|
||||
if !elem_ty.is_copy_modulo_regions(
|
||||
self.tcx,
|
||||
self.param_env,
|
||||
self.source_info.span,
|
||||
) {
|
||||
self.require_unsafe(
|
||||
"assignment to non-`Copy` union field",
|
||||
"the previous content of the field will be dropped, which \
|
||||
|
@ -88,7 +88,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
return Err(ErrorReported);
|
||||
}
|
||||
|
||||
if self.type_is_known_to_be_sized(t, span) {
|
||||
if self.type_is_known_to_be_sized_modulo_regions(t, span) {
|
||||
return Ok(Some(PointerKind::Thin));
|
||||
}
|
||||
|
||||
@ -397,7 +397,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
|
||||
self.expr_ty,
|
||||
self.cast_ty);
|
||||
|
||||
if !fcx.type_is_known_to_be_sized(self.cast_ty, self.span) {
|
||||
if !fcx.type_is_known_to_be_sized_modulo_regions(self.cast_ty, self.span) {
|
||||
self.report_cast_to_unsized_type(fcx);
|
||||
} else if self.expr_ty.references_error() || self.cast_ty.references_error() {
|
||||
// No sense in giving duplicate error messages
|
||||
@ -618,8 +618,8 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
fn type_is_known_to_be_sized(&self, ty: Ty<'tcx>, span: Span) -> bool {
|
||||
fn type_is_known_to_be_sized_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool {
|
||||
let lang_item = self.tcx.require_lang_item(lang_items::SizedTraitLangItem);
|
||||
traits::type_known_to_meet_bound(self, self.param_env, ty, lang_item, span)
|
||||
traits::type_known_to_meet_bound_modulo_regions(self, self.param_env, ty, lang_item, span)
|
||||
}
|
||||
}
|
||||
|
@ -353,9 +353,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
// Maybe add `*`? Only if `T: Copy`.
|
||||
_ => {
|
||||
if !self.infcx.type_moves_by_default(self.param_env,
|
||||
checked,
|
||||
sp) {
|
||||
if self.infcx.type_is_copy_modulo_regions(self.param_env,
|
||||
checked,
|
||||
sp) {
|
||||
// do not suggest if the span comes from a macro (#52783)
|
||||
if let (Ok(code),
|
||||
true) = (cm.span_to_snippet(sp), sp == expr.span) {
|
||||
|
@ -262,9 +262,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
let mut suggested_deref = false;
|
||||
if let Ref(_, mut rty, _) = lhs_ty.sty {
|
||||
if {
|
||||
!self.infcx.type_moves_by_default(self.param_env,
|
||||
rty,
|
||||
lhs_expr.span) &&
|
||||
self.infcx.type_is_copy_modulo_regions(self.param_env,
|
||||
rty,
|
||||
lhs_expr.span) &&
|
||||
self.lookup_op_method(rty,
|
||||
&[rhs_ty],
|
||||
Op::Binary(op, is_assign))
|
||||
@ -334,9 +334,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
let mut suggested_deref = false;
|
||||
if let Ref(_, mut rty, _) = lhs_ty.sty {
|
||||
if {
|
||||
!self.infcx.type_moves_by_default(self.param_env,
|
||||
rty,
|
||||
lhs_expr.span) &&
|
||||
self.infcx.type_is_copy_modulo_regions(self.param_env,
|
||||
rty,
|
||||
lhs_expr.span) &&
|
||||
self.lookup_op_method(rty,
|
||||
&[rhs_ty],
|
||||
Op::Binary(op, is_assign))
|
||||
|
@ -873,7 +873,7 @@ fn receiver_is_valid<'fcx, 'tcx, 'gcx>(
|
||||
trait_ref.to_predicate()
|
||||
);
|
||||
|
||||
if !fcx.predicate_must_hold(&obligation) {
|
||||
if !fcx.predicate_must_hold_modulo_regions(&obligation) {
|
||||
debug!("receiver_is_valid: type `{:?}` does not implement `Receiver` trait",
|
||||
receiver_ty);
|
||||
return false
|
||||
|
@ -73,6 +73,10 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
|
||||
cause.add_intercrate_ambiguity_hint(&mut err);
|
||||
}
|
||||
|
||||
if overlap.involves_placeholder {
|
||||
traits::add_placeholder_note(&mut err);
|
||||
}
|
||||
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
@ -1,39 +0,0 @@
|
||||
// run-pass
|
||||
// Test that two distinct impls which match subtypes of one another
|
||||
// yield coherence errors (or not) depending on the variance.
|
||||
|
||||
trait Contravariant {
|
||||
fn foo(&self) { }
|
||||
}
|
||||
|
||||
impl Contravariant for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 {
|
||||
}
|
||||
|
||||
impl Contravariant for for<'a> fn(&'a u8, &'a u8) -> &'a u8 {
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
trait Covariant {
|
||||
fn foo(&self) { }
|
||||
}
|
||||
|
||||
impl Covariant for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 {
|
||||
}
|
||||
|
||||
impl Covariant for for<'a> fn(&'a u8, &'a u8) -> &'a u8 {
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
trait Invariant {
|
||||
fn foo(&self) { }
|
||||
}
|
||||
|
||||
impl Invariant for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 {
|
||||
}
|
||||
|
||||
impl Invariant for for<'a> fn(&'a u8, &'a u8) -> &'a u8 {
|
||||
}
|
||||
|
||||
fn main() { }
|
@ -77,23 +77,33 @@ fn tuple_four<T>()
|
||||
// not ok for tuple, two lifetimes, and lifetime matching is invariant
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
pub fn call_foo() {
|
||||
foo::<IntStruct>();
|
||||
foo::<UintStruct>(); //~ ERROR type mismatch
|
||||
}
|
||||
|
||||
pub fn call_bar() {
|
||||
bar::<IntStruct>(); //~ ERROR type mismatch
|
||||
bar::<UintStruct>();
|
||||
|
||||
tuple_one::<Tuple>();
|
||||
//~^ ERROR E0277
|
||||
//~| ERROR type mismatch
|
||||
|
||||
tuple_two::<Tuple>();
|
||||
//~^ ERROR E0277
|
||||
//~| ERROR type mismatch
|
||||
|
||||
tuple_three::<Tuple>();
|
||||
|
||||
tuple_four::<Tuple>();
|
||||
//~^ ERROR E0277
|
||||
}
|
||||
|
||||
pub fn call_tuple_one() {
|
||||
tuple_one::<Tuple>();
|
||||
//~^ ERROR not general enough
|
||||
}
|
||||
|
||||
pub fn call_tuple_two() {
|
||||
tuple_two::<Tuple>();
|
||||
//~^ ERROR not general enough
|
||||
}
|
||||
|
||||
pub fn call_tuple_three() {
|
||||
tuple_three::<Tuple>();
|
||||
}
|
||||
|
||||
pub fn call_tuple_four() {
|
||||
tuple_four::<Tuple>();
|
||||
//~^ ERROR not general enough
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
@ -17,7 +17,7 @@ LL | | }
|
||||
| |_^
|
||||
|
||||
error[E0271]: type mismatch resolving `for<'x> <IntStruct as TheTrait<&'x isize>>::A == &'x usize`
|
||||
--> $DIR/associated-types-eq-hr.rs:84:5
|
||||
--> $DIR/associated-types-eq-hr.rs:86:5
|
||||
|
|
||||
LL | bar::<IntStruct>(); //~ ERROR type mismatch
|
||||
| ^^^^^^^^^^^^^^^^ expected isize, found usize
|
||||
@ -34,93 +34,36 @@ LL | | // ok for UintStruct, but not IntStruct
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
|
||||
--> $DIR/associated-types-eq-hr.rs:87:5
|
||||
|
|
||||
LL | tuple_one::<Tuple>();
|
||||
| ^^^^^^^^^^^^^^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple`
|
||||
|
|
||||
= help: the following implementations were found:
|
||||
<Tuple as TheTrait<(&'a isize, &'a isize)>>
|
||||
note: required by `tuple_one`
|
||||
--> $DIR/associated-types-eq-hr.rs:56:1
|
||||
|
|
||||
LL | / fn tuple_one<T>()
|
||||
LL | | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>
|
||||
LL | | {
|
||||
LL | | // not ok for tuple, two lifetimes and we pick first
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error[E0271]: type mismatch resolving `for<'x, 'y> <Tuple as TheTrait<(&'x isize, &'y isize)>>::A == &'x isize`
|
||||
--> $DIR/associated-types-eq-hr.rs:87:5
|
||||
|
|
||||
LL | tuple_one::<Tuple>();
|
||||
| ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime
|
||||
|
|
||||
note: required by `tuple_one`
|
||||
--> $DIR/associated-types-eq-hr.rs:56:1
|
||||
|
|
||||
LL | / fn tuple_one<T>()
|
||||
LL | | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>
|
||||
LL | | {
|
||||
LL | | // not ok for tuple, two lifetimes and we pick first
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
|
||||
error: implementation of `TheTrait` is not general enough
|
||||
--> $DIR/associated-types-eq-hr.rs:91:5
|
||||
|
|
||||
LL | tuple_two::<Tuple>();
|
||||
| ^^^^^^^^^^^^^^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple`
|
||||
LL | tuple_one::<Tuple>();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: the following implementations were found:
|
||||
<Tuple as TheTrait<(&'a isize, &'a isize)>>
|
||||
note: required by `tuple_two`
|
||||
--> $DIR/associated-types-eq-hr.rs:62:1
|
||||
|
|
||||
LL | / fn tuple_two<T>()
|
||||
LL | | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>
|
||||
LL | | {
|
||||
LL | | // not ok for tuple, two lifetimes and we pick second
|
||||
LL | | }
|
||||
| |_^
|
||||
= note: Due to a where-clause on `tuple_one`,
|
||||
= note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>` for any two lifetimes `'0` and `'1`
|
||||
= note: but `Tuple` only implements `TheTrait<(&'2 isize, &'2 isize)>` for some lifetime `'2`
|
||||
|
||||
error[E0271]: type mismatch resolving `for<'x, 'y> <Tuple as TheTrait<(&'x isize, &'y isize)>>::A == &'y isize`
|
||||
--> $DIR/associated-types-eq-hr.rs:91:5
|
||||
error: implementation of `TheTrait` is not general enough
|
||||
--> $DIR/associated-types-eq-hr.rs:96:5
|
||||
|
|
||||
LL | tuple_two::<Tuple>();
|
||||
| ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: required by `tuple_two`
|
||||
--> $DIR/associated-types-eq-hr.rs:62:1
|
||||
|
|
||||
LL | / fn tuple_two<T>()
|
||||
LL | | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>
|
||||
LL | | {
|
||||
LL | | // not ok for tuple, two lifetimes and we pick second
|
||||
LL | | }
|
||||
| |_^
|
||||
= note: Due to a where-clause on `tuple_two`,
|
||||
= note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>` for any two lifetimes `'0` and `'1`
|
||||
= note: but `Tuple` only implements `TheTrait<(&'2 isize, &'2 isize)>` for some lifetime `'2`
|
||||
|
||||
error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
|
||||
--> $DIR/associated-types-eq-hr.rs:97:5
|
||||
error: implementation of `TheTrait` is not general enough
|
||||
--> $DIR/associated-types-eq-hr.rs:105:5
|
||||
|
|
||||
LL | tuple_four::<Tuple>();
|
||||
| ^^^^^^^^^^^^^^^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple`
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: the following implementations were found:
|
||||
<Tuple as TheTrait<(&'a isize, &'a isize)>>
|
||||
note: required by `tuple_four`
|
||||
--> $DIR/associated-types-eq-hr.rs:74:1
|
||||
|
|
||||
LL | / fn tuple_four<T>()
|
||||
LL | | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize)>
|
||||
LL | | {
|
||||
LL | | // not ok for tuple, two lifetimes, and lifetime matching is invariant
|
||||
LL | | }
|
||||
| |_^
|
||||
= note: Due to a where-clause on `tuple_four`,
|
||||
= note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>` for any two lifetimes `'0` and `'1`
|
||||
= note: but `Tuple` only implements `TheTrait<(&'2 isize, &'2 isize)>` for some lifetime `'2`
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
Some errors occurred: E0271, E0277.
|
||||
For more information about an error, try `rustc --explain E0271`.
|
||||
For more information about this error, try `rustc --explain E0271`.
|
||||
|
@ -1,17 +1,12 @@
|
||||
error[E0271]: type mismatch resolving `for<'a> <&'a _ as Mirror>::Image == _`
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/higher-ranked-projection.rs:25:5
|
||||
|
|
||||
LL | foo(());
|
||||
| ^^^ expected bound lifetime parameter 'a, found concrete lifetime
|
||||
| ^^^ one type is more general than the other
|
||||
|
|
||||
note: required by `foo`
|
||||
--> $DIR/higher-ranked-projection.rs:14:1
|
||||
|
|
||||
LL | / fn foo<U, T>(_t: T)
|
||||
LL | | where for<'a> &'a T: Mirror<Image=U>
|
||||
LL | | {}
|
||||
| |__^
|
||||
= note: expected type `Mirror`
|
||||
found type `Mirror`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0271`.
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
@ -3,8 +3,7 @@ error: compilation successful
|
||||
|
|
||||
LL | / fn main() { //[good]~ ERROR compilation successful
|
||||
LL | | foo(());
|
||||
LL | | //[bad]~^ ERROR type mismatch resolving `for<'a> <&'a _ as Mirror>::Image == _`
|
||||
LL | | //[bad]~| expected bound lifetime parameter 'a, found concrete lifetime
|
||||
LL | | //[bad]~^ ERROR E0308
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
|
@ -23,6 +23,5 @@ fn foo<U, T>(_t: T)
|
||||
#[rustc_error]
|
||||
fn main() { //[good]~ ERROR compilation successful
|
||||
foo(());
|
||||
//[bad]~^ ERROR type mismatch resolving `for<'a> <&'a _ as Mirror>::Image == _`
|
||||
//[bad]~| expected bound lifetime parameter 'a, found concrete lifetime
|
||||
//[bad]~^ ERROR E0308
|
||||
}
|
||||
|
@ -28,14 +28,14 @@ fn expect_free_supply_bound() {
|
||||
// Here, we are given a function whose region is bound at closure level,
|
||||
// but we expect one bound in the argument. Error results.
|
||||
with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
|
||||
//~^ ERROR type mismatch in closure arguments
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn expect_bound_supply_free_from_fn<'x>(x: &'x u32) {
|
||||
// Here, we are given a `fn(&u32)` but we expect a `fn(&'x
|
||||
// u32)`. In principle, this could be ok, but we demand equality.
|
||||
with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
|
||||
//~^ ERROR type mismatch in closure arguments
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn expect_bound_supply_free_from_closure() {
|
||||
@ -43,8 +43,9 @@ fn expect_bound_supply_free_from_closure() {
|
||||
// bound at the closure level, but we expect something bound at
|
||||
// the argument level.
|
||||
type Foo<'a> = fn(&'a u32);
|
||||
with_closure_expecting_fn_with_bound_region(|_x: Foo<'_>, y| {});
|
||||
//~^ ERROR type mismatch in closure arguments
|
||||
with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| {
|
||||
//~^ ERROR mismatched types
|
||||
});
|
||||
}
|
||||
|
||||
fn expect_bound_supply_bound<'x>(x: &'x u32) {
|
||||
|
@ -36,58 +36,33 @@ note: ...does not necessarily outlive the anonymous lifetime #2 defined on the b
|
||||
LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0631]: type mismatch in closure arguments
|
||||
--> $DIR/expect-fn-supply-fn.rs:30:5
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/expect-fn-supply-fn.rs:30:52
|
||||
|
|
||||
LL | with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _`
|
||||
| |
|
||||
| expected signature of `for<'a, 'r> fn(fn(&'a u32), &'r i32) -> _`
|
||||
| ^^^^^^^^ one type is more general than the other
|
||||
|
|
||||
note: required by `with_closure_expecting_fn_with_free_region`
|
||||
--> $DIR/expect-fn-supply-fn.rs:1:1
|
||||
|
|
||||
LL | / fn with_closure_expecting_fn_with_free_region<F>(_: F)
|
||||
LL | | where F: for<'a> FnOnce(fn(&'a u32), &i32)
|
||||
LL | | {
|
||||
LL | | }
|
||||
| |_^
|
||||
= note: expected type `fn(&u32)`
|
||||
found type `for<'r> fn(&'r u32)`
|
||||
|
||||
error[E0631]: type mismatch in closure arguments
|
||||
--> $DIR/expect-fn-supply-fn.rs:37:5
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/expect-fn-supply-fn.rs:37:53
|
||||
|
|
||||
LL | with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------- found signature of `fn(fn(&'x u32), _) -> _`
|
||||
| |
|
||||
| expected signature of `for<'r> fn(for<'s> fn(&'s u32), &'r i32) -> _`
|
||||
| ^^^^^^^^^^^ one type is more general than the other
|
||||
|
|
||||
note: required by `with_closure_expecting_fn_with_bound_region`
|
||||
--> $DIR/expect-fn-supply-fn.rs:6:1
|
||||
|
|
||||
LL | / fn with_closure_expecting_fn_with_bound_region<F>(_: F)
|
||||
LL | | where F: FnOnce(fn(&u32), &i32)
|
||||
LL | | {
|
||||
LL | | }
|
||||
| |_^
|
||||
= note: expected type `for<'r> fn(&'r u32)`
|
||||
found type `fn(&'x u32)`
|
||||
|
||||
error[E0631]: type mismatch in closure arguments
|
||||
--> $DIR/expect-fn-supply-fn.rs:46:5
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/expect-fn-supply-fn.rs:46:53
|
||||
|
|
||||
LL | with_closure_expecting_fn_with_bound_region(|_x: Foo<'_>, y| {});
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `for<'r> fn(fn(&'r u32), _) -> _`
|
||||
| |
|
||||
| expected signature of `for<'r> fn(for<'s> fn(&'s u32), &'r i32) -> _`
|
||||
LL | with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| {
|
||||
| ^^^^^^^ one type is more general than the other
|
||||
|
|
||||
note: required by `with_closure_expecting_fn_with_bound_region`
|
||||
--> $DIR/expect-fn-supply-fn.rs:6:1
|
||||
|
|
||||
LL | / fn with_closure_expecting_fn_with_bound_region<F>(_: F)
|
||||
LL | | where F: FnOnce(fn(&u32), &i32)
|
||||
LL | | {
|
||||
LL | | }
|
||||
| |_^
|
||||
= note: expected type `for<'r> fn(&'r u32)`
|
||||
found type `fn(&u32)`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
Some errors occurred: E0308, E0631.
|
||||
For more information about an error, try `rustc --explain E0308`.
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
15
src/test/ui/coherence/coherence-subtyping.rs
Normal file
15
src/test/ui/coherence/coherence-subtyping.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// Test that two distinct impls which match subtypes of one another
|
||||
// yield coherence errors (or not) depending on the variance.
|
||||
|
||||
trait TheTrait {
|
||||
fn foo(&self) { }
|
||||
}
|
||||
|
||||
impl TheTrait for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 {
|
||||
}
|
||||
|
||||
impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 {
|
||||
//~^ ERROR
|
||||
}
|
||||
|
||||
fn main() { }
|
14
src/test/ui/coherence/coherence-subtyping.stderr
Normal file
14
src/test/ui/coherence/coherence-subtyping.stderr
Normal file
@ -0,0 +1,14 @@
|
||||
error[E0119]: conflicting implementations of trait `TheTrait` for type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`:
|
||||
--> $DIR/coherence-subtyping.rs:11:1
|
||||
|
|
||||
LL | impl TheTrait for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 {
|
||||
| --------------------------------------------------------- first implementation here
|
||||
...
|
||||
LL | impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
|
||||
|
|
||||
= note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0119`.
|
@ -27,7 +27,8 @@ fn main() {
|
||||
yield;
|
||||
assert_foo(x);
|
||||
};
|
||||
assert_foo(gen); //~ ERROR the trait bound `No: Foo` is not satisfied
|
||||
assert_foo(gen);
|
||||
//~^ ERROR implementation of `Foo` is not general enough
|
||||
|
||||
// Allow impls which matches any lifetime
|
||||
let x = &OnlyFooIfRef(No);
|
||||
@ -44,5 +45,6 @@ fn main() {
|
||||
yield;
|
||||
assert_foo(a);
|
||||
};
|
||||
assert_foo(gen); //~ ERROR the requirement `for<'r, 's> 'r : 's` is not satisfied
|
||||
assert_foo(gen);
|
||||
//~^ ERROR not general enough
|
||||
}
|
||||
|
@ -1,37 +1,20 @@
|
||||
error[E0277]: the trait bound `No: Foo` is not satisfied in `[generator@$DIR/auto-trait-regions.rs:25:15: 29:6 x:&&OnlyFooIfStaticRef for<'r> {&'r OnlyFooIfStaticRef, ()}]`
|
||||
error: implementation of `Foo` is not general enough
|
||||
--> $DIR/auto-trait-regions.rs:30:5
|
||||
|
|
||||
LL | assert_foo(gen); //~ ERROR the trait bound `No: Foo` is not satisfied
|
||||
| ^^^^^^^^^^ within `[generator@$DIR/auto-trait-regions.rs:25:15: 29:6 x:&&OnlyFooIfStaticRef for<'r> {&'r OnlyFooIfStaticRef, ()}]`, the trait `Foo` is not implemented for `No`
|
||||
|
|
||||
= help: the following implementations were found:
|
||||
<No as Foo>
|
||||
= note: required because it appears within the type `OnlyFooIfStaticRef`
|
||||
= note: required because it appears within the type `&OnlyFooIfStaticRef`
|
||||
= note: required because it appears within the type `for<'r> {&'r OnlyFooIfStaticRef, ()}`
|
||||
= note: required because it appears within the type `[generator@$DIR/auto-trait-regions.rs:25:15: 29:6 x:&&OnlyFooIfStaticRef for<'r> {&'r OnlyFooIfStaticRef, ()}]`
|
||||
note: required by `assert_foo`
|
||||
--> $DIR/auto-trait-regions.rs:20:1
|
||||
|
|
||||
LL | fn assert_foo<T: Foo>(f: T) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0279]: the requirement `for<'r, 's> 'r : 's` is not satisfied (`expected bound lifetime parameter, found concrete lifetime`)
|
||||
--> $DIR/auto-trait-regions.rs:47:5
|
||||
|
|
||||
LL | assert_foo(gen); //~ ERROR the requirement `for<'r, 's> 'r : 's` is not satisfied
|
||||
LL | assert_foo(gen);
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: required because of the requirements on the impl of `for<'r, 's> Foo` for `A<'_, '_>`
|
||||
= note: required because it appears within the type `for<'r, 's> {A<'r, 's>, ()}`
|
||||
= note: required because it appears within the type `[generator@$DIR/auto-trait-regions.rs:42:15: 46:6 for<'r, 's> {A<'r, 's>, ()}]`
|
||||
note: required by `assert_foo`
|
||||
--> $DIR/auto-trait-regions.rs:20:1
|
||||
= note: `&'0 OnlyFooIfStaticRef` must implement `Foo` for any lifetime `'0`
|
||||
= note: but `&'1 OnlyFooIfStaticRef` only implements `Foo` for the lifetime `'1`
|
||||
|
||||
error: implementation of `Foo` is not general enough
|
||||
--> $DIR/auto-trait-regions.rs:48:5
|
||||
|
|
||||
LL | fn assert_foo<T: Foo>(f: T) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | assert_foo(gen);
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: `A<'0, '1>` must implement `Foo` for any two lifetimes `'0` and `'1`
|
||||
= note: but `A<'_, '2>` only implements `Foo` for the lifetime `'2`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors occurred: E0277, E0279.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
|
@ -2,7 +2,7 @@ error[E0308]: mismatched types
|
||||
--> $DIR/hr-subtype.rs:39:26
|
||||
|
|
||||
LL | gimme::<$t1>(None::<$t2>);
|
||||
| ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
|
||||
| ^^^^^^^^^^^ one type is more general than the other
|
||||
...
|
||||
LL | / check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32,
|
||||
LL | | for<'a> fn(&'a u32, &'a u32) -> &'a u32) }
|
||||
|
@ -1,16 +1,14 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/hr-subtype.rs:39:26
|
||||
error: compilation successful
|
||||
--> $DIR/hr-subtype.rs:96:1
|
||||
|
|
||||
LL | gimme::<$t1>(None::<$t2>);
|
||||
| ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
|
||||
...
|
||||
LL | / check! { bound_a_b_vs_bound_a: (for<'a,'b> fn(&'a u32, &'b u32),
|
||||
LL | | for<'a> fn(&'a u32, &'a u32)) }
|
||||
| |__________________________________________________________________- in this macro invocation
|
||||
|
|
||||
= note: expected type `std::option::Option<for<'a, 'b> fn(&'a u32, &'b u32)>`
|
||||
found type `std::option::Option<for<'a> fn(&'a u32, &'a u32)>`
|
||||
LL | / fn main() {
|
||||
LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
|
||||
LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
|
||||
LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
|
||||
... |
|
||||
LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
@ -1,12 +1,12 @@
|
||||
error: compilation successful
|
||||
--> $DIR/hr-subtype.rs:100:1
|
||||
--> $DIR/hr-subtype.rs:96:1
|
||||
|
|
||||
LL | / fn main() {
|
||||
LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
|
||||
LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
|
||||
LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
|
||||
LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful
|
||||
LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful
|
||||
... |
|
||||
LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
error: compilation successful
|
||||
--> $DIR/hr-subtype.rs:100:1
|
||||
--> $DIR/hr-subtype.rs:96:1
|
||||
|
|
||||
LL | / fn main() {
|
||||
LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
|
||||
LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
|
||||
LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
|
||||
LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful
|
||||
LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful
|
||||
... |
|
||||
LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
|
@ -2,7 +2,7 @@ error[E0308]: mismatched types
|
||||
--> $DIR/hr-subtype.rs:39:26
|
||||
|
|
||||
LL | gimme::<$t1>(None::<$t2>);
|
||||
| ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
|
||||
| ^^^^^^^^^^^ one type is more general than the other
|
||||
...
|
||||
LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32),
|
||||
LL | | fn(&'x u32)) }
|
||||
|
@ -1,16 +1,14 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/hr-subtype.rs:39:26
|
||||
error: compilation successful
|
||||
--> $DIR/hr-subtype.rs:96:1
|
||||
|
|
||||
LL | gimme::<$t1>(None::<$t2>);
|
||||
| ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
|
||||
...
|
||||
LL | / check! { bound_co_a_b_vs_bound_co_a: (for<'a,'b> fn(Co<'a>, Co<'b>),
|
||||
LL | | for<'a> fn(Co<'a>, Co<'a>)) }
|
||||
| |______________________________________________________________________- in this macro invocation
|
||||
|
|
||||
= note: expected type `std::option::Option<for<'a, 'b> fn(Co<'a>, Co<'b>)>`
|
||||
found type `std::option::Option<for<'a> fn(Co<'a>, Co<'a>)>`
|
||||
LL | / fn main() {
|
||||
LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
|
||||
LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
|
||||
LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
|
||||
... |
|
||||
LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
@ -1,16 +1,14 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/hr-subtype.rs:39:26
|
||||
error: compilation successful
|
||||
--> $DIR/hr-subtype.rs:96:1
|
||||
|
|
||||
LL | gimme::<$t1>(None::<$t2>);
|
||||
| ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
|
||||
...
|
||||
LL | / check! { bound_co_a_co_b_ret_contra_a: (for<'a,'b> fn(Co<'a>, Co<'b>) -> Contra<'a>,
|
||||
LL | | for<'a> fn(Co<'a>, Co<'a>) -> Contra<'a>) }
|
||||
| |______________________________________________________________________________________- in this macro invocation
|
||||
|
|
||||
= note: expected type `std::option::Option<for<'a, 'b> fn(Co<'a>, Co<'b>) -> Contra<'a>>`
|
||||
found type `std::option::Option<for<'a> fn(Co<'a>, Co<'a>) -> Contra<'a>>`
|
||||
LL | / fn main() {
|
||||
LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
|
||||
LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
|
||||
LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
|
||||
... |
|
||||
LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
@ -1,12 +1,12 @@
|
||||
error: compilation successful
|
||||
--> $DIR/hr-subtype.rs:100:1
|
||||
--> $DIR/hr-subtype.rs:96:1
|
||||
|
|
||||
LL | / fn main() {
|
||||
LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
|
||||
LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
|
||||
LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
|
||||
LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful
|
||||
LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful
|
||||
... |
|
||||
LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
|
@ -1,16 +1,14 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/hr-subtype.rs:39:26
|
||||
error: compilation successful
|
||||
--> $DIR/hr-subtype.rs:96:1
|
||||
|
|
||||
LL | gimme::<$t1>(None::<$t2>);
|
||||
| ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
|
||||
...
|
||||
LL | / check! { bound_contra_a_contra_b_ret_co_a: (for<'a,'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>,
|
||||
LL | | for<'a> fn(Contra<'a>, Contra<'a>) -> Co<'a>) }
|
||||
| |______________________________________________________________________________________________- in this macro invocation
|
||||
|
|
||||
= note: expected type `std::option::Option<for<'a, 'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>>`
|
||||
found type `std::option::Option<for<'a> fn(Contra<'a>, Contra<'a>) -> Co<'a>>`
|
||||
LL | / fn main() {
|
||||
LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
|
||||
LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
|
||||
LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
|
||||
... |
|
||||
LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
@ -2,7 +2,7 @@ error[E0308]: mismatched types
|
||||
--> $DIR/hr-subtype.rs:39:26
|
||||
|
|
||||
LL | gimme::<$t1>(None::<$t2>);
|
||||
| ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
|
||||
| ^^^^^^^^^^^ one type is more general than the other
|
||||
...
|
||||
LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>),
|
||||
LL | | for<'a> fn(Inv<'a>, Inv<'a>)) }
|
||||
|
@ -1,12 +1,12 @@
|
||||
error: compilation successful
|
||||
--> $DIR/hr-subtype.rs:100:1
|
||||
--> $DIR/hr-subtype.rs:96:1
|
||||
|
|
||||
LL | / fn main() {
|
||||
LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
|
||||
LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
|
||||
LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
|
||||
LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful
|
||||
LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful
|
||||
... |
|
||||
LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
error: compilation successful
|
||||
--> $DIR/hr-subtype.rs:100:1
|
||||
--> $DIR/hr-subtype.rs:96:1
|
||||
|
|
||||
LL | / fn main() {
|
||||
LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
|
||||
LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
|
||||
LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
|
||||
LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful
|
||||
LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful
|
||||
... |
|
||||
LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
|
@ -31,21 +31,17 @@ macro_rules! check {
|
||||
#[cfg($rev)]
|
||||
fn subtype<'x,'y:'x,'z:'y>() {
|
||||
gimme::<$t2>(None::<$t1>);
|
||||
//[free_inv_x_vs_free_inv_y]~^ ERROR mismatched types
|
||||
//[free_inv_x_vs_free_inv_y]~^ ERROR
|
||||
}
|
||||
|
||||
#[cfg($rev)]
|
||||
fn supertype<'x,'y:'x,'z:'y>() {
|
||||
gimme::<$t1>(None::<$t2>);
|
||||
//[bound_a_vs_free_x]~^ ERROR mismatched types
|
||||
//[free_x_vs_free_y]~^^ ERROR mismatched types
|
||||
//[bound_inv_a_b_vs_bound_inv_a]~^^^ ERROR mismatched types
|
||||
//[bound_a_b_ret_a_vs_bound_a_ret_a]~^^^^ ERROR mismatched types
|
||||
//[free_inv_x_vs_free_inv_y]~^^^^^ ERROR mismatched types
|
||||
//[bound_a_b_vs_bound_a]~^^^^^^ ERROR mismatched types
|
||||
//[bound_co_a_b_vs_bound_co_a]~^^^^^^^ ERROR mismatched types
|
||||
//[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^ ERROR mismatched types
|
||||
//[bound_co_a_co_b_ret_contra_a]~^^^^^^^^^ ERROR mismatched types
|
||||
//[bound_a_vs_free_x]~^ ERROR
|
||||
//[free_x_vs_free_y]~^^ ERROR
|
||||
//[bound_inv_a_b_vs_bound_inv_a]~^^^ ERROR
|
||||
//[bound_a_b_ret_a_vs_bound_a_ret_a]~^^^^ ERROR
|
||||
//[free_inv_x_vs_free_inv_y]~^^^^^ ERROR
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -103,4 +99,8 @@ fn main() {
|
||||
//[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
|
||||
//[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful
|
||||
//[free_x_vs_free_x]~^^^^^ ERROR compilation successful
|
||||
//[bound_a_b_vs_bound_a]~^^^^^^ ERROR compilation successful
|
||||
//[bound_co_a_co_b_ret_contra_a]~^^^^^^^ ERROR compilation successful
|
||||
//[bound_co_a_b_vs_bound_co_a]~^^^^^^^^ ERROR compilation successful
|
||||
//[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
|
||||
}
|
||||
|
24
src/test/ui/hrtb/hrtb-cache-issue-54302.rs
Normal file
24
src/test/ui/hrtb/hrtb-cache-issue-54302.rs
Normal file
@ -0,0 +1,24 @@
|
||||
// Regression test for #54302.
|
||||
//
|
||||
// We were incorrectly using the "evaluation cache" (which ignored
|
||||
// region results) to conclude that `&'static str: Deserialize`, even
|
||||
// though it would require that `for<'de> 'de: 'static`, which is
|
||||
// clearly false.
|
||||
|
||||
trait Deserialize<'de> {}
|
||||
|
||||
trait DeserializeOwned: for<'de> Deserialize<'de> {}
|
||||
impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
|
||||
|
||||
// Based on this impl, `&'static str` only implements Deserialize<'static>.
|
||||
// It does not implement for<'de> Deserialize<'de>.
|
||||
impl<'de: 'a, 'a> Deserialize<'de> for &'a str {}
|
||||
|
||||
fn main() {
|
||||
fn assert_deserialize_owned<T: DeserializeOwned>() {}
|
||||
assert_deserialize_owned::<&'static str>(); //~ ERROR
|
||||
|
||||
// It correctly does not implement for<'de> Deserialize<'de>.
|
||||
// fn assert_hrtb<T: for<'de> Deserialize<'de>>() {}
|
||||
// assert_hrtb::<&'static str>();
|
||||
}
|
11
src/test/ui/hrtb/hrtb-cache-issue-54302.stderr
Normal file
11
src/test/ui/hrtb/hrtb-cache-issue-54302.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
error: implementation of `Deserialize` is not general enough
|
||||
--> $DIR/hrtb-cache-issue-54302.rs:19:5
|
||||
|
|
||||
LL | assert_deserialize_owned::<&'static str>(); //~ ERROR
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `&'static str` must implement `Deserialize<'0>` for any lifetime `'0`
|
||||
= note: but `&str` only implements `Deserialize<'1>` for some lifetime `'1`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -25,6 +25,6 @@ impl<'a> Foo<(&'a isize, &'a isize)> for SomeStruct
|
||||
}
|
||||
|
||||
fn a() { want_foo1::<SomeStruct>(); } // OK -- foo wants just one region
|
||||
fn b() { want_foo2::<SomeStruct>(); } //~ ERROR E0277
|
||||
fn b() { want_foo2::<SomeStruct>(); } //~ ERROR
|
||||
|
||||
fn main() { }
|
||||
|
@ -1,20 +1,12 @@
|
||||
error[E0277]: the trait bound `for<'a, 'b> SomeStruct: Foo<(&'a isize, &'b isize)>` is not satisfied
|
||||
error: implementation of `Foo` is not general enough
|
||||
--> $DIR/hrtb-conflate-regions.rs:28:10
|
||||
|
|
||||
LL | fn b() { want_foo2::<SomeStruct>(); } //~ ERROR E0277
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a, 'b> Foo<(&'a isize, &'b isize)>` is not implemented for `SomeStruct`
|
||||
LL | fn b() { want_foo2::<SomeStruct>(); } //~ ERROR
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: the following implementations were found:
|
||||
<SomeStruct as Foo<(&'a isize, &'a isize)>>
|
||||
note: required by `want_foo2`
|
||||
--> $DIR/hrtb-conflate-regions.rs:8:1
|
||||
|
|
||||
LL | / fn want_foo2<T>()
|
||||
LL | | where T : for<'a,'b> Foo<(&'a isize, &'b isize)>
|
||||
LL | | {
|
||||
LL | | }
|
||||
| |_^
|
||||
= note: Due to a where-clause on `want_foo2`,
|
||||
= note: `SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>` for any two lifetimes `'0` and `'1`
|
||||
= note: but `SomeStruct` only implements `Foo<(&'2 isize, &'2 isize)>` for some lifetime `'2`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
18
src/test/ui/hrtb/hrtb-exists-forall-fn.rs
Normal file
18
src/test/ui/hrtb/hrtb-exists-forall-fn.rs
Normal file
@ -0,0 +1,18 @@
|
||||
// Test a `exists<'a> { forall<'b> { 'a = 'b } }` pattern -- which should not compile!
|
||||
//
|
||||
// In particular, we test this pattern in trait solving, where it is not connected
|
||||
// to any part of the source code.
|
||||
|
||||
fn foo<'a>() -> fn(&'a u32) {
|
||||
panic!()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Here, proving that `fn(&'a u32) <: for<'b> fn(&'b u32)`:
|
||||
//
|
||||
// - instantiates `'b` with a placeholder `!b`,
|
||||
// - requires that `&!b u32 <: &'a u32` and hence that `!b: 'a`,
|
||||
// - but we can never know this.
|
||||
|
||||
let _: for<'b> fn(&'b u32) = foo(); //~ ERROR mismatched types
|
||||
}
|
12
src/test/ui/hrtb/hrtb-exists-forall-fn.stderr
Normal file
12
src/test/ui/hrtb/hrtb-exists-forall-fn.stderr
Normal file
@ -0,0 +1,12 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/hrtb-exists-forall-fn.rs:17:34
|
||||
|
|
||||
LL | let _: for<'b> fn(&'b u32) = foo(); //~ ERROR mismatched types
|
||||
| ^^^^^ one type is more general than the other
|
||||
|
|
||||
= note: expected type `for<'b> fn(&'b u32)`
|
||||
found type `fn(&u32)`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
35
src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs
Normal file
35
src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs
Normal file
@ -0,0 +1,35 @@
|
||||
// Test a `exists<'a> { forall<'b> { 'a = 'b } }` pattern -- which should not compile!
|
||||
//
|
||||
// In particular, we test this pattern in trait solving, where it is not connected
|
||||
// to any part of the source code.
|
||||
//
|
||||
// compile-pass
|
||||
|
||||
trait Trait<T> {}
|
||||
|
||||
fn foo<T>()
|
||||
where
|
||||
T: Trait<for<'b> fn(&'b u32)>,
|
||||
{
|
||||
}
|
||||
|
||||
impl<'a> Trait<fn(&'a u32)> for () {}
|
||||
|
||||
fn main() {
|
||||
// Here, proving that `(): Trait<for<'b> fn(&'b u32)>` uses the impl:
|
||||
//
|
||||
// - The impl provides the clause `forall<'a> { (): Trait<fn(&'a u32)> }`
|
||||
// - We instantiate `'a` existentially to get `(): Trait<fn(&?a u32)>`
|
||||
// - We unify `fn(&?a u32)` with `for<'b> fn(&'b u32)` -- this does a
|
||||
// "bidirectional" subtyping check, so we wind up with:
|
||||
// - `fn(&?a u32) <: for<'b> fn(&'b u32)` :-
|
||||
// - `&'!b u32 <: &?a u32`
|
||||
// - `!'b: ?a` -- solveable if `?a` is inferred to `'empty`
|
||||
// - `for<'b> fn(&'b u32) <: fn(&?a u32)` :-
|
||||
// - `&?a u32 u32 <: &?b u32`
|
||||
// - `?a: ?b` -- solveable if `?b` is also inferred to `'empty`
|
||||
// - So the subtyping check succeeds, somewhat surprisingly.
|
||||
// This is because we can use `'empty`.
|
||||
|
||||
foo::<()>();
|
||||
}
|
37
src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs
Normal file
37
src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs
Normal file
@ -0,0 +1,37 @@
|
||||
// Test a `exists<'a> { forall<'b> { 'a = 'b } }` pattern -- which should not compile!
|
||||
//
|
||||
// In particular, we test this pattern in trait solving, where it is not connected
|
||||
// to any part of the source code.
|
||||
//
|
||||
// compile-pass
|
||||
|
||||
trait Trait<T> {}
|
||||
|
||||
fn foo<T>()
|
||||
where
|
||||
T: Trait<for<'b> fn(fn(&'b u32))>,
|
||||
{
|
||||
}
|
||||
|
||||
impl<'a> Trait<fn(fn(&'a u32))> for () {}
|
||||
|
||||
fn main() {
|
||||
// Here, proving that `(): Trait<for<'b> fn(&'b u32)>` uses the impl:
|
||||
//
|
||||
// - The impl provides the clause `forall<'a> { (): Trait<fn(fn(&'a u32))> }`
|
||||
// - We instantiate `'a` existentially to get `(): Trait<fn(fn(&?a u32))>`
|
||||
// - We unify `fn(fn(&?a u32))` with `for<'b> fn(fn(&'b u32))` -- this does a
|
||||
// "bidirectional" subtyping check, so we wind up with:
|
||||
// - `fn(fn(&?a u32)) <: for<'b> fn(fn(&'b u32))` :-
|
||||
// - `fn(&!b u32) <: fn(&?a u32)`
|
||||
// - `&?a u32 <: &!b u32`
|
||||
// - `?a: !'b` -- solveable if `?a` is inferred to `'static`
|
||||
// - `for<'b> fn(fn(&'b u32)) <: fn(fn(&?a u32))` :-
|
||||
// - `fn(&?a u32) <: fn(&?b u32)`
|
||||
// - `&?b u32 <: &?a u32`
|
||||
// - `?b: ?a` -- solveable if `?b` is inferred to `'static`
|
||||
// - So the subtyping check succeeds, somewhat surprisingly.
|
||||
// This is because we can use `'static`.
|
||||
|
||||
foo::<()>();
|
||||
}
|
29
src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs
Normal file
29
src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs
Normal file
@ -0,0 +1,29 @@
|
||||
// Test a `exists<'a> { forall<'b> { 'a = 'b } }` pattern -- which should not compile!
|
||||
//
|
||||
// In particular, we test this pattern in trait solving, where it is not connected
|
||||
// to any part of the source code.
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
trait Trait<T> {}
|
||||
|
||||
fn foo<T>()
|
||||
where
|
||||
T: Trait<for<'b> fn(Cell<&'b u32>)>,
|
||||
{
|
||||
}
|
||||
|
||||
impl<'a> Trait<fn(Cell<&'a u32>)> for () {}
|
||||
|
||||
fn main() {
|
||||
// Here, proving that `(): Trait<for<'b> fn(&'b u32)>` uses the impl:
|
||||
//
|
||||
// - The impl provides the clause `forall<'a> { (): Trait<fn(&'a u32)> }`
|
||||
// - We instantiate `'a` existentially to get `(): Trait<fn(&?a u32)>`
|
||||
// - We unify `fn(&?a u32)` with `for<'b> fn(&'b u32)`
|
||||
// - This requires (among other things) instantiating `'b` universally,
|
||||
// yielding `fn(&!b u32)`, in a fresh universe U1
|
||||
// - So we get `?a = !b` but the universe U0 assigned to `?a` cannot name `!b`.
|
||||
|
||||
foo::<()>(); //~ ERROR not general enough
|
||||
}
|
12
src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr
Normal file
12
src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr
Normal file
@ -0,0 +1,12 @@
|
||||
error: implementation of `Trait` is not general enough
|
||||
--> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5
|
||||
|
|
||||
LL | foo::<()>(); //~ ERROR not general enough
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: Due to a where-clause on `foo`,
|
||||
= note: `()` must implement `Trait<for<'b> fn(std::cell::Cell<&'b u32>)>`
|
||||
= note: but `()` only implements `Trait<fn(std::cell::Cell<&'0 u32>)>` for some lifetime `'0`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -44,7 +44,7 @@ fn want_qux<B>(b: &B)
|
||||
where B : Qux
|
||||
{
|
||||
want_foo_for_any_tcx(b);
|
||||
want_bar_for_any_ccx(b); //~ ERROR E0277
|
||||
want_bar_for_any_ccx(b); //~ ERROR
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,19 +1,12 @@
|
||||
error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:5
|
||||
|
|
||||
LL | want_bar_for_any_ccx(b); //~ ERROR E0277
|
||||
| ^^^^^^^^^^^^^^^^^^^^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B`
|
||||
LL | want_bar_for_any_ccx(b); //~ ERROR
|
||||
| ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
||||
|
|
||||
= help: consider adding a `where for<'ccx> B: Bar<'ccx>` bound
|
||||
note: required by `want_bar_for_any_ccx`
|
||||
--> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:31:1
|
||||
|
|
||||
LL | / fn want_bar_for_any_ccx<B>(b: &B)
|
||||
LL | | where B : for<'ccx> Bar<'ccx>
|
||||
LL | | {
|
||||
LL | | }
|
||||
| |_^
|
||||
= note: expected type `for<'ccx> Bar<'ccx>`
|
||||
found type `Bar<'static>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
@ -15,7 +15,7 @@ fn want_foo_for_some_tcx<'x,F>(f: &'x F)
|
||||
where F : Foo<'x>
|
||||
{
|
||||
want_foo_for_some_tcx(f);
|
||||
want_foo_for_any_tcx(f); //~ ERROR E0277
|
||||
want_foo_for_any_tcx(f); //~ ERROR E0308
|
||||
}
|
||||
|
||||
fn want_foo_for_any_tcx<F>(f: &F)
|
||||
@ -32,7 +32,7 @@ fn want_bar_for_some_ccx<'x,B>(b: &B)
|
||||
want_foo_for_any_tcx(b);
|
||||
|
||||
want_bar_for_some_ccx(b);
|
||||
want_bar_for_any_ccx(b); //~ ERROR E0277
|
||||
want_bar_for_any_ccx(b); //~ ERROR E0308
|
||||
}
|
||||
|
||||
fn want_bar_for_any_ccx<B>(b: &B)
|
||||
|
@ -1,40 +1,21 @@
|
||||
error[E0277]: the trait bound `for<'tcx> F: Foo<'tcx>` is not satisfied
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/hrtb-higher-ranker-supertraits.rs:18:5
|
||||
|
|
||||
LL | want_foo_for_any_tcx(f); //~ ERROR E0277
|
||||
| ^^^^^^^^^^^^^^^^^^^^ the trait `for<'tcx> Foo<'tcx>` is not implemented for `F`
|
||||
LL | want_foo_for_any_tcx(f); //~ ERROR E0308
|
||||
| ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
||||
|
|
||||
= help: consider adding a `where for<'tcx> F: Foo<'tcx>` bound
|
||||
note: required by `want_foo_for_any_tcx`
|
||||
--> $DIR/hrtb-higher-ranker-supertraits.rs:21:1
|
||||
|
|
||||
LL | / fn want_foo_for_any_tcx<F>(f: &F)
|
||||
LL | | where F : for<'tcx> Foo<'tcx>
|
||||
LL | | {
|
||||
LL | | want_foo_for_some_tcx(f);
|
||||
LL | | want_foo_for_any_tcx(f);
|
||||
LL | | }
|
||||
| |_^
|
||||
= note: expected type `for<'tcx> Foo<'tcx>`
|
||||
found type `Foo<'x>`
|
||||
|
||||
error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/hrtb-higher-ranker-supertraits.rs:35:5
|
||||
|
|
||||
LL | want_bar_for_any_ccx(b); //~ ERROR E0277
|
||||
| ^^^^^^^^^^^^^^^^^^^^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B`
|
||||
LL | want_bar_for_any_ccx(b); //~ ERROR E0308
|
||||
| ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
||||
|
|
||||
= help: consider adding a `where for<'ccx> B: Bar<'ccx>` bound
|
||||
note: required by `want_bar_for_any_ccx`
|
||||
--> $DIR/hrtb-higher-ranker-supertraits.rs:38:1
|
||||
|
|
||||
LL | / fn want_bar_for_any_ccx<B>(b: &B)
|
||||
LL | | where B : for<'ccx> Bar<'ccx>
|
||||
LL | | {
|
||||
LL | | want_foo_for_some_tcx(b);
|
||||
... |
|
||||
LL | | want_bar_for_any_ccx(b);
|
||||
LL | | }
|
||||
| |_^
|
||||
= note: expected type `for<'ccx> Bar<'ccx>`
|
||||
found type `Bar<'x>`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
@ -21,7 +21,13 @@ fn give_any() {
|
||||
struct StaticInt;
|
||||
impl Foo<&'static isize> for StaticInt { }
|
||||
fn give_static() {
|
||||
want_hrtb::<StaticInt>() //~ ERROR `for<'a> StaticInt: Foo<&'a isize>` is not satisfied
|
||||
want_hrtb::<StaticInt>() //~ ERROR
|
||||
}
|
||||
|
||||
// AnyInt implements Foo<&'a isize> for any 'a, so it is a match.
|
||||
impl<'a> Foo<&'a isize> for &'a u32 { }
|
||||
fn give_some<'a>() {
|
||||
want_hrtb::<&'a u32>() //~ ERROR
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
@ -1,20 +1,22 @@
|
||||
error[E0277]: the trait bound `for<'a> StaticInt: Foo<&'a isize>` is not satisfied
|
||||
error: implementation of `Foo` is not general enough
|
||||
--> $DIR/hrtb-just-for-static.rs:24:5
|
||||
|
|
||||
LL | want_hrtb::<StaticInt>() //~ ERROR `for<'a> StaticInt: Foo<&'a isize>` is not satisfied
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Foo<&'a isize>` is not implemented for `StaticInt`
|
||||
LL | want_hrtb::<StaticInt>() //~ ERROR
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: the following implementations were found:
|
||||
<StaticInt as Foo<&'static isize>>
|
||||
note: required by `want_hrtb`
|
||||
--> $DIR/hrtb-just-for-static.rs:8:1
|
||||
= note: Due to a where-clause on `want_hrtb`,
|
||||
= note: `StaticInt` must implement `Foo<&'0 isize>` for any lifetime `'0`
|
||||
= note: but `StaticInt` only implements `Foo<&'1 isize>` for some lifetime `'1`
|
||||
|
||||
error: implementation of `Foo` is not general enough
|
||||
--> $DIR/hrtb-just-for-static.rs:30:5
|
||||
|
|
||||
LL | / fn want_hrtb<T>()
|
||||
LL | | where T : for<'a> Foo<&'a isize>
|
||||
LL | | {
|
||||
LL | | }
|
||||
| |_^
|
||||
LL | want_hrtb::<&'a u32>() //~ ERROR
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: Due to a where-clause on `want_hrtb`,
|
||||
= note: `&'a u32` must implement `Foo<&'0 isize>` for any lifetime `'0`
|
||||
= note: but `&'1 u32` only implements `Foo<&'1 isize>` for the lifetime `'1`
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
@ -43,7 +43,7 @@ fn foo_hrtb_bar_not<'b,T>(mut t: T)
|
||||
// be implemented. Thus to satisfy `&mut T : for<'a> Foo<&'a
|
||||
// isize>`, we require `T : for<'a> Bar<&'a isize>`, but the where
|
||||
// clause only specifies `T : Bar<&'b isize>`.
|
||||
foo_hrtb_bar_not(&mut t); //~ ERROR `for<'a> T: Bar<&'a isize>` is not satisfied
|
||||
foo_hrtb_bar_not(&mut t); //~ ERROR E0308
|
||||
}
|
||||
|
||||
fn foo_hrtb_bar_hrtb<T>(mut t: T)
|
||||
|
@ -1,23 +1,12 @@
|
||||
error[E0277]: the trait bound `for<'a> T: Bar<&'a isize>` is not satisfied
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/hrtb-perfect-forwarding.rs:46:5
|
||||
|
|
||||
LL | foo_hrtb_bar_not(&mut t); //~ ERROR `for<'a> T: Bar<&'a isize>` is not satisfied
|
||||
| ^^^^^^^^^^^^^^^^ the trait `for<'a> Bar<&'a isize>` is not implemented for `T`
|
||||
LL | foo_hrtb_bar_not(&mut t); //~ ERROR E0308
|
||||
| ^^^^^^^^^^^^^^^^ one type is more general than the other
|
||||
|
|
||||
= help: consider adding a `where for<'a> T: Bar<&'a isize>` bound
|
||||
= note: required because of the requirements on the impl of `for<'a> Foo<&'a isize>` for `&mut T`
|
||||
note: required by `foo_hrtb_bar_not`
|
||||
--> $DIR/hrtb-perfect-forwarding.rs:39:1
|
||||
|
|
||||
LL | / fn foo_hrtb_bar_not<'b,T>(mut t: T)
|
||||
LL | | where T : for<'a> Foo<&'a isize> + Bar<&'b isize>
|
||||
LL | | {
|
||||
LL | | // Not OK -- The forwarding impl for `Foo` requires that `Bar` also
|
||||
... |
|
||||
LL | | foo_hrtb_bar_not(&mut t); //~ ERROR `for<'a> T: Bar<&'a isize>` is not satisfied
|
||||
LL | | }
|
||||
| |_^
|
||||
= note: expected type `Foo<&'a isize>`
|
||||
found type `Foo<&isize>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
@ -19,7 +19,6 @@ pub trait Process<'a> {
|
||||
fn push_process<P>(process: P) where P: Process<'static> {
|
||||
let _: Box<for<'b> Wrap<'b>> = Box::new(Wrapper(process));
|
||||
//~^ ERROR is not an iterator
|
||||
//~| ERROR is not satisfied
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,23 +1,14 @@
|
||||
error[E0277]: the trait bound `for<'b> P: Process<'b>` is not satisfied
|
||||
error[E0277]: `<P as Process<'_>>::Item` is not an iterator
|
||||
--> $DIR/issue-22872.rs:20:36
|
||||
|
|
||||
LL | let _: Box<for<'b> Wrap<'b>> = Box::new(Wrapper(process));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'b> Process<'b>` is not implemented for `P`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ `<P as Process<'_>>::Item` is not an iterator
|
||||
|
|
||||
= help: consider adding a `where for<'b> P: Process<'b>` bound
|
||||
= help: the trait `std::iter::Iterator` is not implemented for `<P as Process<'_>>::Item`
|
||||
= help: consider adding a `where <P as Process<'_>>::Item: std::iter::Iterator` bound
|
||||
= note: required because of the requirements on the impl of `for<'b> Wrap<'b>` for `Wrapper<P>`
|
||||
= note: required for the cast to the object type `dyn for<'b> Wrap<'b>`
|
||||
|
||||
error[E0277]: `<P as Process<'b>>::Item` is not an iterator
|
||||
--> $DIR/issue-22872.rs:20:36
|
||||
|
|
||||
LL | let _: Box<for<'b> Wrap<'b>> = Box::new(Wrapper(process));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ `<P as Process<'b>>::Item` is not an iterator
|
||||
|
|
||||
= help: the trait `for<'b> std::iter::Iterator` is not implemented for `<P as Process<'b>>::Item`
|
||||
= note: required because of the requirements on the impl of `for<'b> Wrap<'b>` for `Wrapper<P>`
|
||||
= note: required for the cast to the object type `dyn for<'b> Wrap<'b>`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
@ -3,6 +3,5 @@ fn main() {
|
||||
|
||||
fn foo(x: Box<Fn(&i32)>) {}
|
||||
let bar = Box::new(|x: &i32| {}) as Box<Fn(_)>;
|
||||
foo(bar); //~ ERROR mismatched types
|
||||
//~| expected concrete lifetime, found bound lifetime parameter
|
||||
foo(bar); //~ ERROR E0308
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-40000.rs:6:9
|
||||
|
|
||||
LL | foo(bar); //~ ERROR mismatched types
|
||||
| ^^^ expected concrete lifetime, found bound lifetime parameter
|
||||
LL | foo(bar); //~ ERROR E0308
|
||||
| ^^^ one type is more general than the other
|
||||
|
|
||||
= note: expected type `std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r i32) + 'static)>`
|
||||
found type `std::boxed::Box<dyn std::ops::Fn(_)>`
|
||||
= note: expected type `dyn for<'r> std::ops::Fn(&'r i32)`
|
||||
found type `dyn std::ops::Fn(&i32)`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -61,25 +61,25 @@ impl<T> RefFoo<T> for T where for<'a> &'a T: Foo<'static, T> {
|
||||
fn coerce_lifetime1(a: &u32) -> &'static u32
|
||||
{
|
||||
<u32 as RefFoo<u32>>::ref_foo(a)
|
||||
//~^ ERROR the trait bound `for<'a> &'a u32: Foo2<'_, u32>` is not satisfied
|
||||
//~^ ERROR not general enough
|
||||
}
|
||||
|
||||
fn coerce_lifetime2(a: &i32) -> &'static i32
|
||||
{
|
||||
<i32 as RefFoo<i32>>::ref_foo(a)
|
||||
//~^ ERROR the requirement `for<'a> 'a : ` is not satisfied
|
||||
//~^ ERROR not general enough
|
||||
}
|
||||
|
||||
fn coerce_lifetime3(a: &u64) -> &'static u64
|
||||
{
|
||||
<u64 as RefFoo<u64>>::ref_foo(a)
|
||||
//~^ ERROR type mismatch resolving `for<'a> <&'a u64 as Mirror>::Image == &u64`
|
||||
//~^ ERROR not general enough
|
||||
}
|
||||
|
||||
fn coerce_lifetime4(a: &i64) -> &'static i64
|
||||
{
|
||||
<i64 as RefFoo<i64>>::ref_foo(a)
|
||||
//~^ ERROR type mismatch resolving `for<'a> <&'a i64 as Mirror>::Image == &i64`
|
||||
//~^ ERROR not general enough
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,65 +1,38 @@
|
||||
error[E0277]: the trait bound `for<'a> &'a u32: Foo2<'_, u32>` is not satisfied
|
||||
error: implementation of `Foo` is not general enough
|
||||
--> $DIR/issue-54302-cases.rs:63:5
|
||||
|
|
||||
LL | <u32 as RefFoo<u32>>::ref_foo(a)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Foo2<'_, u32>` is not implemented for `&'a u32`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: the following implementations were found:
|
||||
<&'x u32 as Foo2<'x, u32>>
|
||||
= note: required because of the requirements on the impl of `for<'a> Foo<'static, u32>` for `&'a u32`
|
||||
= note: required because of the requirements on the impl of `RefFoo<u32>` for `u32`
|
||||
note: required by `RefFoo::ref_foo`
|
||||
--> $DIR/issue-54302-cases.rs:51:5
|
||||
|
|
||||
LL | fn ref_foo(&self) -> &'static T;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: `&'0 u32` must implement `Foo<'static, u32>` for any lifetime `'0`
|
||||
= note: but `&'1 _` only implements `Foo<'_, _>` for the lifetime `'1`
|
||||
|
||||
error[E0279]: the requirement `for<'a> 'a : ` is not satisfied (`expected bound lifetime parameter 'a, found concrete lifetime`)
|
||||
error: implementation of `Foo` is not general enough
|
||||
--> $DIR/issue-54302-cases.rs:69:5
|
||||
|
|
||||
LL | <i32 as RefFoo<i32>>::ref_foo(a)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: required because of the requirements on the impl of `for<'a> Foo2<'_, i32>` for `&'a i32`
|
||||
= note: required because of the requirements on the impl of `for<'a> Foo<'static, i32>` for `&'a i32`
|
||||
= note: required because of the requirements on the impl of `RefFoo<i32>` for `i32`
|
||||
note: required by `RefFoo::ref_foo`
|
||||
--> $DIR/issue-54302-cases.rs:51:5
|
||||
|
|
||||
LL | fn ref_foo(&self) -> &'static T;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: `&'0 i32` must implement `Foo<'static, i32>` for any lifetime `'0`
|
||||
= note: but `&'1 _` only implements `Foo<'_, _>` for the lifetime `'1`
|
||||
|
||||
error[E0271]: type mismatch resolving `for<'a> <&'a u64 as Mirror>::Image == &u64`
|
||||
error: implementation of `Foo` is not general enough
|
||||
--> $DIR/issue-54302-cases.rs:75:5
|
||||
|
|
||||
LL | <u64 as RefFoo<u64>>::ref_foo(a)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'a, found concrete lifetime
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: required because of the requirements on the impl of `for<'a> Foo2<'_, u64>` for `&'a u64`
|
||||
= note: required because of the requirements on the impl of `for<'a> Foo<'static, u64>` for `&'a u64`
|
||||
= note: required because of the requirements on the impl of `RefFoo<u64>` for `u64`
|
||||
note: required by `RefFoo::ref_foo`
|
||||
--> $DIR/issue-54302-cases.rs:51:5
|
||||
|
|
||||
LL | fn ref_foo(&self) -> &'static T;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: `&'0 u64` must implement `Foo<'static, u64>` for any lifetime `'0`
|
||||
= note: but `&'1 _` only implements `Foo<'_, _>` for the lifetime `'1`
|
||||
|
||||
error[E0271]: type mismatch resolving `for<'a> <&'a i64 as Mirror>::Image == &i64`
|
||||
error: implementation of `Foo` is not general enough
|
||||
--> $DIR/issue-54302-cases.rs:81:5
|
||||
|
|
||||
LL | <i64 as RefFoo<i64>>::ref_foo(a)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'a, found concrete lifetime
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: required because of the requirements on the impl of `for<'a> Foo2<'_, i64>` for `&'a i64`
|
||||
= note: required because of the requirements on the impl of `for<'a> Foo<'static, i64>` for `&'a i64`
|
||||
= note: required because of the requirements on the impl of `RefFoo<i64>` for `i64`
|
||||
note: required by `RefFoo::ref_foo`
|
||||
--> $DIR/issue-54302-cases.rs:51:5
|
||||
|
|
||||
LL | fn ref_foo(&self) -> &'static T;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: `&'0 i64` must implement `Foo<'static, i64>` for any lifetime `'0`
|
||||
= note: but `&'1 _` only implements `Foo<'_, _>` for the lifetime `'1`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors occurred: E0271, E0277, E0279.
|
||||
For more information about an error, try `rustc --explain E0271`.
|
||||
|
@ -11,7 +11,7 @@ fn main() {
|
||||
// Then why does it implement DeserializeOwned? This compiles.
|
||||
fn assert_deserialize_owned<T: DeserializeOwned>() {}
|
||||
assert_deserialize_owned::<&'static str>();
|
||||
//~^ ERROR the requirement `for<'de> 'de : ` is not satisfied
|
||||
//~^ ERROR not general enough
|
||||
|
||||
// It correctly does not implement for<'de> Deserialize<'de>.
|
||||
//fn assert_hrtb<T: for<'de> Deserialize<'de>>() {}
|
||||
|
@ -1,17 +1,11 @@
|
||||
error[E0279]: the requirement `for<'de> 'de : ` is not satisfied (`expected bound lifetime parameter 'de, found concrete lifetime`)
|
||||
error: implementation of `Deserialize` is not general enough
|
||||
--> $DIR/issue-54302.rs:13:5
|
||||
|
|
||||
LL | assert_deserialize_owned::<&'static str>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: required because of the requirements on the impl of `for<'de> Deserialize<'de>` for `&'static str`
|
||||
= note: required because of the requirements on the impl of `DeserializeOwned` for `&'static str`
|
||||
note: required by `main::assert_deserialize_owned`
|
||||
--> $DIR/issue-54302.rs:12:5
|
||||
|
|
||||
LL | fn assert_deserialize_owned<T: DeserializeOwned>() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: `&'static str` must implement `Deserialize<'0>` for any lifetime `'0`
|
||||
= note: but `&str` only implements `Deserialize<'1>` for some lifetime `'1`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0279`.
|
||||
|
@ -1,11 +1,16 @@
|
||||
// Test that we give a note when the old LUB/GLB algorithm would have
|
||||
// succeeded but the new code (which is stricter) gives an error.
|
||||
// succeeded but the new code (which requires equality) gives an
|
||||
// error. However, now that we handle subtyping correctly, we no
|
||||
// longer get an error, because we recognize these two types as
|
||||
// equivalent!
|
||||
//
|
||||
// compile-pass
|
||||
|
||||
fn foo(
|
||||
x: fn(&u8, &u8),
|
||||
y: for<'a> fn(&'a u8, &'a u8),
|
||||
) {
|
||||
let z = match 22 { //~ ERROR incompatible types
|
||||
let z = match 22 {
|
||||
0 => x,
|
||||
_ => y,
|
||||
};
|
||||
|
@ -1,17 +0,0 @@
|
||||
error[E0308]: match arms have incompatible types
|
||||
--> $DIR/old-lub-glb-hr.rs:8:13
|
||||
|
|
||||
LL | let z = match 22 { //~ ERROR incompatible types
|
||||
| _____________^
|
||||
LL | | 0 => x,
|
||||
LL | | _ => y,
|
||||
| | - match arm with an incompatible type
|
||||
LL | | };
|
||||
| |_____^ expected bound lifetime parameter, found concrete lifetime
|
||||
|
|
||||
= note: expected type `for<'r, 's> fn(&'r u8, &'s u8)`
|
||||
found type `for<'a> fn(&'a u8, &'a u8)`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
@ -7,7 +7,7 @@ fn foo(
|
||||
x: &for<'a, 'b> Foo<&'a u8, &'b u8>,
|
||||
y: &for<'a> Foo<&'a u8, &'a u8>,
|
||||
) {
|
||||
let z = match 22 { //~ ERROR incompatible types
|
||||
let z = match 22 { //~ ERROR E0308
|
||||
0 => x,
|
||||
_ => y,
|
||||
};
|
||||
|
@ -1,16 +1,15 @@
|
||||
error[E0308]: match arms have incompatible types
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/old-lub-glb-object.rs:10:13
|
||||
|
|
||||
LL | let z = match 22 { //~ ERROR incompatible types
|
||||
LL | let z = match 22 { //~ ERROR E0308
|
||||
| _____________^
|
||||
LL | | 0 => x,
|
||||
LL | | _ => y,
|
||||
| | - match arm with an incompatible type
|
||||
LL | | };
|
||||
| |_____^ expected bound lifetime parameter 'a, found concrete lifetime
|
||||
| |_____^ one type is more general than the other
|
||||
|
|
||||
= note: expected type `&dyn for<'a, 'b> Foo<&'a u8, &'b u8>`
|
||||
found type `&dyn for<'a> Foo<&'a u8, &'a u8>`
|
||||
= note: expected type `dyn for<'a, 'b> Foo<&'a u8, &'b u8>`
|
||||
found type `dyn for<'a> Foo<&'a u8, &'a u8>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user