Rollup merge of #93892 - compiler-errors:issue-92917, r=jackh726,nikomatsakis
Only mark projection as ambiguous if GAT substs are constrained A slightly more targeted version of #92917, where we only give up with ambiguity if we infer something about the GATs substs when probing for a projection candidate. fixes #93874 also note (but like the previous PR, does not fix) #91762 r? `@jackh726` cc `@nikomatsakis` who reviewed #92917
This commit is contained in:
commit
1e2f63de0a
6 changed files with 100 additions and 43 deletions
|
@ -263,7 +263,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
|
||||||
let index = self.values().push(TypeVariableData { origin });
|
let index = self.values().push(TypeVariableData { origin });
|
||||||
assert_eq!(eq_key.vid.as_u32(), index as u32);
|
assert_eq!(eq_key.vid.as_u32(), index as u32);
|
||||||
|
|
||||||
debug!("new_var(index={:?}, universe={:?}, origin={:?}", eq_key.vid, universe, origin,);
|
debug!("new_var(index={:?}, universe={:?}, origin={:?})", eq_key.vid, universe, origin);
|
||||||
|
|
||||||
eq_key.vid
|
eq_key.vid
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
|
||||||
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
|
use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
|
||||||
use crate::traits::error_reporting::InferCtxtExt as _;
|
use crate::traits::error_reporting::InferCtxtExt as _;
|
||||||
|
use crate::traits::select::ProjectionMatchesProjection;
|
||||||
use rustc_data_structures::sso::SsoHashSet;
|
use rustc_data_structures::sso::SsoHashSet;
|
||||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
use rustc_errors::ErrorReported;
|
use rustc_errors::ErrorReported;
|
||||||
|
@ -1075,16 +1076,6 @@ fn project<'cx, 'tcx>(
|
||||||
return Ok(Projected::Progress(Progress::error(selcx.tcx())));
|
return Ok(Projected::Progress(Progress::error(selcx.tcx())));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the obligation contains any inference types or consts in associated
|
|
||||||
// type substs, then we don't assemble any candidates.
|
|
||||||
// This isn't really correct, but otherwise we can end up in a case where
|
|
||||||
// we constrain inference variables by selecting a single predicate, when
|
|
||||||
// we need to stay general. See issue #91762.
|
|
||||||
let (_, predicate_own_substs) = obligation.predicate.trait_ref_and_own_substs(selcx.tcx());
|
|
||||||
if predicate_own_substs.iter().any(|g| g.has_infer_types_or_consts()) {
|
|
||||||
return Err(ProjectionError::TooManyCandidates);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut candidates = ProjectionCandidateSet::None;
|
let mut candidates = ProjectionCandidateSet::None;
|
||||||
|
|
||||||
// Make sure that the following procedures are kept in order. ParamEnv
|
// Make sure that the following procedures are kept in order. ParamEnv
|
||||||
|
@ -1182,7 +1173,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
|
||||||
ProjectionCandidate::TraitDef,
|
ProjectionCandidate::TraitDef,
|
||||||
bounds.iter(),
|
bounds.iter(),
|
||||||
true,
|
true,
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// In the case of a trait object like
|
/// In the case of a trait object like
|
||||||
|
@ -1247,28 +1238,35 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
|
||||||
let bound_predicate = predicate.kind();
|
let bound_predicate = predicate.kind();
|
||||||
if let ty::PredicateKind::Projection(data) = predicate.kind().skip_binder() {
|
if let ty::PredicateKind::Projection(data) = predicate.kind().skip_binder() {
|
||||||
let data = bound_predicate.rebind(data);
|
let data = bound_predicate.rebind(data);
|
||||||
let same_def_id = data.projection_def_id() == obligation.predicate.item_def_id;
|
if data.projection_def_id() != obligation.predicate.item_def_id {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let is_match = same_def_id
|
let is_match = infcx.probe(|_| {
|
||||||
&& infcx.probe(|_| {
|
selcx.match_projection_projections(
|
||||||
selcx.match_projection_projections(
|
obligation,
|
||||||
obligation,
|
data,
|
||||||
data,
|
potentially_unnormalized_candidates,
|
||||||
potentially_unnormalized_candidates,
|
)
|
||||||
)
|
});
|
||||||
});
|
|
||||||
|
|
||||||
if is_match {
|
match is_match {
|
||||||
candidate_set.push_candidate(ctor(data));
|
ProjectionMatchesProjection::Yes => {
|
||||||
|
candidate_set.push_candidate(ctor(data));
|
||||||
|
|
||||||
if potentially_unnormalized_candidates
|
if potentially_unnormalized_candidates
|
||||||
&& !obligation.predicate.has_infer_types_or_consts()
|
&& !obligation.predicate.has_infer_types_or_consts()
|
||||||
{
|
{
|
||||||
// HACK: Pick the first trait def candidate for a fully
|
// HACK: Pick the first trait def candidate for a fully
|
||||||
// inferred predicate. This is to allow duplicates that
|
// inferred predicate. This is to allow duplicates that
|
||||||
// differ only in normalization.
|
// differ only in normalization.
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
ProjectionMatchesProjection::Ambiguous => {
|
||||||
|
candidate_set.mark_ambiguous();
|
||||||
|
}
|
||||||
|
ProjectionMatchesProjection::No => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1494,12 +1494,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return `Yes` if the obligation's predicate type applies to the env_predicate, and
|
||||||
|
/// `No` if it does not. Return `Ambiguous` in the case that the projection type is a GAT,
|
||||||
|
/// and applying this env_predicate constrains any of the obligation's GAT substitutions.
|
||||||
|
///
|
||||||
|
/// This behavior is a somewhat of a hack to prevent overconstraining inference variables
|
||||||
|
/// in cases like #91762.
|
||||||
pub(super) fn match_projection_projections(
|
pub(super) fn match_projection_projections(
|
||||||
&mut self,
|
&mut self,
|
||||||
obligation: &ProjectionTyObligation<'tcx>,
|
obligation: &ProjectionTyObligation<'tcx>,
|
||||||
env_predicate: PolyProjectionPredicate<'tcx>,
|
env_predicate: PolyProjectionPredicate<'tcx>,
|
||||||
potentially_unnormalized_candidates: bool,
|
potentially_unnormalized_candidates: bool,
|
||||||
) -> bool {
|
) -> ProjectionMatchesProjection {
|
||||||
let mut nested_obligations = Vec::new();
|
let mut nested_obligations = Vec::new();
|
||||||
let (infer_predicate, _) = self.infcx.replace_bound_vars_with_fresh_vars(
|
let (infer_predicate, _) = self.infcx.replace_bound_vars_with_fresh_vars(
|
||||||
obligation.cause.span,
|
obligation.cause.span,
|
||||||
|
@ -1521,7 +1527,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
infer_predicate.projection_ty
|
infer_predicate.projection_ty
|
||||||
};
|
};
|
||||||
|
|
||||||
self.infcx
|
let is_match = self
|
||||||
|
.infcx
|
||||||
.at(&obligation.cause, obligation.param_env)
|
.at(&obligation.cause, obligation.param_env)
|
||||||
.sup(obligation.predicate, infer_projection)
|
.sup(obligation.predicate, infer_projection)
|
||||||
.map_or(false, |InferOk { obligations, value: () }| {
|
.map_or(false, |InferOk { obligations, value: () }| {
|
||||||
|
@ -1530,7 +1537,26 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
nested_obligations.into_iter().chain(obligations),
|
nested_obligations.into_iter().chain(obligations),
|
||||||
)
|
)
|
||||||
.map_or(false, |res| res.may_apply())
|
.map_or(false, |res| res.may_apply())
|
||||||
})
|
});
|
||||||
|
|
||||||
|
if is_match {
|
||||||
|
let generics = self.tcx().generics_of(obligation.predicate.item_def_id);
|
||||||
|
// FIXME(generic-associated-types): Addresses aggressive inference in #92917.
|
||||||
|
// If this type is a GAT, and of the GAT substs resolve to something new,
|
||||||
|
// that means that we must have newly inferred something about the GAT.
|
||||||
|
// We should give up in that case.
|
||||||
|
if !generics.params.is_empty()
|
||||||
|
&& obligation.predicate.substs[generics.parent_count..]
|
||||||
|
.iter()
|
||||||
|
.any(|&p| p.has_infer_types_or_consts() && self.infcx.shallow_resolve(p) != p)
|
||||||
|
{
|
||||||
|
ProjectionMatchesProjection::Ambiguous
|
||||||
|
} else {
|
||||||
|
ProjectionMatchesProjection::Yes
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ProjectionMatchesProjection::No
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -2709,3 +2735,9 @@ impl<'o, 'tcx> fmt::Debug for TraitObligationStack<'o, 'tcx> {
|
||||||
write!(f, "TraitObligationStack({:?})", self.obligation)
|
write!(f, "TraitObligationStack({:?})", self.obligation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum ProjectionMatchesProjection {
|
||||||
|
Yes,
|
||||||
|
Ambiguous,
|
||||||
|
No,
|
||||||
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ impl<T> UnsafeCopy for T {}
|
||||||
fn main() {
|
fn main() {
|
||||||
let b = Box::new(42usize);
|
let b = Box::new(42usize);
|
||||||
let copy = <()>::copy(&b);
|
let copy = <()>::copy(&b);
|
||||||
//~^ type annotations needed
|
|
||||||
|
|
||||||
let raw_b = Box::deref(&b) as *const _;
|
let raw_b = Box::deref(&b) as *const _;
|
||||||
let raw_copy = Box::deref(©) as *const _;
|
let raw_copy = Box::deref(©) as *const _;
|
||||||
|
|
|
@ -27,13 +27,6 @@ help: consider restricting type parameter `T`
|
||||||
LL | type Copy<T: std::clone::Clone>: Copy = Box<T>;
|
LL | type Copy<T: std::clone::Clone>: Copy = Box<T>;
|
||||||
| +++++++++++++++++++
|
| +++++++++++++++++++
|
||||||
|
|
||||||
error[E0282]: type annotations needed
|
error: aborting due to 2 previous errors
|
||||||
--> $DIR/issue-74824.rs:19:16
|
|
||||||
|
|
|
||||||
LL | let copy = <()>::copy(&b);
|
|
||||||
| ^^^^^^^^^^ cannot infer type for type parameter `T` declared on the associated function `copy`
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
For more information about this error, try `rustc --explain E0277`.
|
||||||
|
|
||||||
Some errors have detailed explanations: E0277, E0282.
|
|
||||||
For more information about an error, try `rustc --explain E0277`.
|
|
||||||
|
|
35
src/test/ui/generic-associated-types/issue-93874.rs
Normal file
35
src/test/ui/generic-associated-types/issue-93874.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![feature(generic_associated_types)]
|
||||||
|
|
||||||
|
pub trait Build {
|
||||||
|
type Output<O>;
|
||||||
|
fn build<O>(self, input: O) -> Self::Output<O>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IdentityBuild;
|
||||||
|
impl Build for IdentityBuild {
|
||||||
|
type Output<O> = O;
|
||||||
|
fn build<O>(self, input: O) -> Self::Output<O> {
|
||||||
|
input
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn a() {
|
||||||
|
let _x: u8 = IdentityBuild.build(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn b() {
|
||||||
|
let _x: Vec<u8> = IdentityBuild.build(Vec::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn c() {
|
||||||
|
let mut f = IdentityBuild.build(|| ());
|
||||||
|
(f)();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
a();
|
||||||
|
b();
|
||||||
|
c();
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue