Auto merge of #93285 - JulianKnodt:const_eq_2, r=oli-obk

Continue work on associated const equality

This actually implements some more complex logic for assigning associated consts to values.
Inside of projection candidates, it now defers to a separate function for either consts or
types. To reduce amount of code, projections are now generic over T, where T is either a Type or
a Const. I can add some comments back later, but this was the fastest way to implement it.

It also now finds the correct type of consts in type_of.

---

The current main TODO is finding the const of the def id for the LeafDef.

Right now it works if the function isn't called, but once you use the trait impl with the bound it fails inside projection.
I was hoping to get some help in getting the `&'tcx ty::Const<'tcx>`, in addition to a bunch of other `todo!()`s which I think may not be hit.

r? `@oli-obk`

Updates #92827
This commit is contained in:
bors 2022-02-01 23:18:01 +00:00
commit 1ea4851715
19 changed files with 379 additions and 181 deletions

View File

@ -2203,6 +2203,12 @@ impl TypeBinding<'_> {
_ => panic!("expected equality type binding for parenthesized generic args"), _ => panic!("expected equality type binding for parenthesized generic args"),
} }
} }
pub fn opt_const(&self) -> Option<&'_ AnonConst> {
match self.kind {
TypeBindingKind::Equality { term: Term::Const(ref c) } => Some(c),
_ => None,
}
}
} }
#[derive(Debug)] #[derive(Debug)]

View File

@ -286,6 +286,26 @@ impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> {
} }
} }
impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> {
fn to_trace(
tcx: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
b: Self,
) -> TypeTrace<'tcx> {
match (a, b) {
(ty::Term::Ty(a), ty::Term::Ty(b)) => {
ToTrace::to_trace(tcx, cause, a_is_expected, a, b)
}
(ty::Term::Const(a), ty::Term::Const(b)) => {
ToTrace::to_trace(tcx, cause, a_is_expected, a, b)
}
(_, _) => todo!(),
}
}
}
impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> { impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
fn to_trace( fn to_trace(
_: TyCtxt<'tcx>, _: TyCtxt<'tcx>,

View File

@ -93,7 +93,7 @@ pub enum ProjectionCacheEntry<'tcx> {
Recur, Recur,
Error, Error,
NormalizedTy { NormalizedTy {
ty: NormalizedTy<'tcx>, ty: Normalized<'tcx, ty::Term<'tcx>>,
/// If we were able to successfully evaluate the /// If we were able to successfully evaluate the
/// corresponding cache entry key during predicate /// corresponding cache entry key during predicate
/// evaluation, then this field stores the final /// evaluation, then this field stores the final
@ -174,7 +174,11 @@ impl<'tcx> ProjectionCache<'_, 'tcx> {
} }
/// Indicates that `key` was normalized to `value`. /// Indicates that `key` was normalized to `value`.
pub fn insert_ty(&mut self, key: ProjectionCacheKey<'tcx>, value: NormalizedTy<'tcx>) { pub fn insert_term(
&mut self,
key: ProjectionCacheKey<'tcx>,
value: Normalized<'tcx, ty::Term<'tcx>>,
) {
debug!( debug!(
"ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}", "ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}",
key, value key, value

View File

@ -867,6 +867,9 @@ impl<'tcx> Term<'tcx> {
pub fn ty(&self) -> Option<Ty<'tcx>> { pub fn ty(&self) -> Option<Ty<'tcx>> {
if let Term::Ty(ty) = self { Some(ty) } else { None } if let Term::Ty(ty) = self { Some(ty) } else { None }
} }
pub fn ct(&self) -> Option<&'tcx Const<'tcx>> {
if let Term::Const(c) = self { Some(c) } else { None }
}
} }
/// This kind of predicate has no *direct* correspondent in the /// This kind of predicate has no *direct* correspondent in the

View File

@ -1373,19 +1373,31 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
| ObligationCauseCode::ObjectCastObligation(_) | ObligationCauseCode::ObjectCastObligation(_)
| ObligationCauseCode::OpaqueType | ObligationCauseCode::OpaqueType
); );
// FIXME(associated_const_equality): Handle Consts here
let data_ty = data.term.ty().unwrap();
if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp( if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp(
is_normalized_ty_expected, is_normalized_ty_expected,
normalized_ty, normalized_ty,
data_ty, data.term,
) { ) {
values = Some(infer::ValuePairs::Types(ExpectedFound::new( values = Some(match (normalized_ty, data.term) {
is_normalized_ty_expected, (ty::Term::Ty(normalized_ty), ty::Term::Ty(ty)) => {
normalized_ty, infer::ValuePairs::Types(ExpectedFound::new(
data_ty, is_normalized_ty_expected,
))); normalized_ty,
ty,
))
}
(ty::Term::Const(normalized_ct), ty::Term::Const(ct)) => {
infer::ValuePairs::Consts(ExpectedFound::new(
is_normalized_ty_expected,
normalized_ct,
ct,
))
}
(_, _) => span_bug!(
obligation.cause.span,
"found const or type where other expected"
),
});
err_buf = error; err_buf = error;
err = &err_buf; err = &err_buf;
} }

View File

@ -2496,7 +2496,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
let try_obligation = self.mk_trait_obligation_with_new_self_ty( let try_obligation = self.mk_trait_obligation_with_new_self_ty(
obligation.param_env, obligation.param_env,
trait_pred, trait_pred,
normalized_ty, normalized_ty.ty().unwrap(),
); );
debug!("suggest_await_before_try: try_trait_obligation {:?}", try_obligation); debug!("suggest_await_before_try: try_trait_obligation {:?}", try_obligation);
if self.predicate_may_hold(&try_obligation) if self.predicate_may_hold(&try_obligation)

View File

@ -200,7 +200,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
debug!(?normalized_ty); debug!(?normalized_ty);
normalized_ty normalized_ty.ty().unwrap()
} }
fn register_predicate_obligation( fn register_predicate_obligation(

View File

@ -22,12 +22,13 @@ use crate::traits::error_reporting::InferCtxtExt as _;
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;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_infer::infer::resolve::OpportunisticRegionResolver;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
use rustc_middle::ty::subst::Subst; use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt};
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use std::collections::BTreeMap; use std::collections::BTreeMap;
@ -44,7 +45,7 @@ pub(super) struct InProgress;
/// When attempting to resolve `<T as TraitRef>::Name` ... /// When attempting to resolve `<T as TraitRef>::Name` ...
#[derive(Debug)] #[derive(Debug)]
pub enum ProjectionTyError<'tcx> { pub enum ProjectionError<'tcx> {
/// ...we found multiple sources of information and couldn't resolve the ambiguity. /// ...we found multiple sources of information and couldn't resolve the ambiguity.
TooManyCandidates, TooManyCandidates,
@ -53,7 +54,7 @@ pub enum ProjectionTyError<'tcx> {
} }
#[derive(PartialEq, Eq, Debug)] #[derive(PartialEq, Eq, Debug)]
enum ProjectionTyCandidate<'tcx> { enum ProjectionCandidate<'tcx> {
/// From a where-clause in the env or object type /// From a where-clause in the env or object type
ParamEnv(ty::PolyProjectionPredicate<'tcx>), ParamEnv(ty::PolyProjectionPredicate<'tcx>),
@ -67,28 +68,28 @@ enum ProjectionTyCandidate<'tcx> {
Select(Selection<'tcx>), Select(Selection<'tcx>),
} }
enum ProjectionTyCandidateSet<'tcx> { enum ProjectionCandidateSet<'tcx> {
None, None,
Single(ProjectionTyCandidate<'tcx>), Single(ProjectionCandidate<'tcx>),
Ambiguous, Ambiguous,
Error(SelectionError<'tcx>), Error(SelectionError<'tcx>),
} }
impl<'tcx> ProjectionTyCandidateSet<'tcx> { impl<'tcx> ProjectionCandidateSet<'tcx> {
fn mark_ambiguous(&mut self) { fn mark_ambiguous(&mut self) {
*self = ProjectionTyCandidateSet::Ambiguous; *self = ProjectionCandidateSet::Ambiguous;
} }
fn mark_error(&mut self, err: SelectionError<'tcx>) { fn mark_error(&mut self, err: SelectionError<'tcx>) {
*self = ProjectionTyCandidateSet::Error(err); *self = ProjectionCandidateSet::Error(err);
} }
// Returns true if the push was successful, or false if the candidate // Returns true if the push was successful, or false if the candidate
// was discarded -- this could be because of ambiguity, or because // was discarded -- this could be because of ambiguity, or because
// a higher-priority candidate is already there. // a higher-priority candidate is already there.
fn push_candidate(&mut self, candidate: ProjectionTyCandidate<'tcx>) -> bool { fn push_candidate(&mut self, candidate: ProjectionCandidate<'tcx>) -> bool {
use self::ProjectionTyCandidate::*; use self::ProjectionCandidate::*;
use self::ProjectionTyCandidateSet::*; use self::ProjectionCandidateSet::*;
// This wacky variable is just used to try and // This wacky variable is just used to try and
// make code readable and avoid confusing paths. // make code readable and avoid confusing paths.
@ -196,7 +197,9 @@ fn project_and_unify_type<'cx, 'tcx>(
debug!(?obligation, "project_and_unify_type"); debug!(?obligation, "project_and_unify_type");
let mut obligations = vec![]; let mut obligations = vec![];
let normalized_ty = match opt_normalize_projection_type(
let infcx = selcx.infcx();
let normalized = match opt_normalize_projection_type(
selcx, selcx,
obligation.param_env, obligation.param_env,
obligation.predicate.projection_ty, obligation.predicate.projection_ty,
@ -208,13 +211,11 @@ fn project_and_unify_type<'cx, 'tcx>(
Ok(None) => return Ok(Ok(None)), Ok(None) => return Ok(Ok(None)),
Err(InProgress) => return Ok(Err(InProgress)), Err(InProgress) => return Ok(Err(InProgress)),
}; };
debug!(?normalized, ?obligations, "project_and_unify_type result");
debug!(?normalized_ty, ?obligations, "project_and_unify_type result"); match infcx
.at(&obligation.cause, obligation.param_env)
let infcx = selcx.infcx(); .eq(normalized, obligation.predicate.term)
// FIXME(associated_const_equality): Handle consts here as well as types. {
let obligation_pred_ty = obligation.predicate.term.ty().unwrap();
match infcx.at(&obligation.cause, obligation.param_env).eq(normalized_ty, obligation_pred_ty) {
Ok(InferOk { obligations: inferred_obligations, value: () }) => { Ok(InferOk { obligations: inferred_obligations, value: () }) => {
obligations.extend(inferred_obligations); obligations.extend(inferred_obligations);
Ok(Ok(Some(obligations))) Ok(Ok(Some(obligations)))
@ -441,7 +442,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
obligations.len = ?self.obligations.len(), obligations.len = ?self.obligations.len(),
"AssocTypeNormalizer: normalized type" "AssocTypeNormalizer: normalized type"
); );
normalized_ty normalized_ty.ty().unwrap()
} }
ty::Projection(data) => { ty::Projection(data) => {
@ -471,6 +472,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
) )
.ok() .ok()
.flatten() .flatten()
.map(|term| term.ty().unwrap())
.map(|normalized_ty| { .map(|normalized_ty| {
PlaceholderReplacer::replace_placeholders( PlaceholderReplacer::replace_placeholders(
infcx, infcx,
@ -793,7 +795,7 @@ pub fn normalize_projection_type<'a, 'b, 'tcx>(
cause: ObligationCause<'tcx>, cause: ObligationCause<'tcx>,
depth: usize, depth: usize,
obligations: &mut Vec<PredicateObligation<'tcx>>, obligations: &mut Vec<PredicateObligation<'tcx>>,
) -> Ty<'tcx> { ) -> Term<'tcx> {
opt_normalize_projection_type( opt_normalize_projection_type(
selcx, selcx,
param_env, param_env,
@ -809,7 +811,10 @@ pub fn normalize_projection_type<'a, 'b, 'tcx>(
// and a deferred predicate to resolve this when more type // and a deferred predicate to resolve this when more type
// information is available. // information is available.
selcx.infcx().infer_projection(param_env, projection_ty, cause, depth + 1, obligations) selcx
.infcx()
.infer_projection(param_env, projection_ty, cause, depth + 1, obligations)
.into()
}) })
} }
@ -831,7 +836,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
cause: ObligationCause<'tcx>, cause: ObligationCause<'tcx>,
depth: usize, depth: usize,
obligations: &mut Vec<PredicateObligation<'tcx>>, obligations: &mut Vec<PredicateObligation<'tcx>>,
) -> Result<Option<Ty<'tcx>>, InProgress> { ) -> Result<Option<Term<'tcx>>, InProgress> {
let infcx = selcx.infcx(); let infcx = selcx.infcx();
// Don't use the projection cache in intercrate mode - // Don't use the projection cache in intercrate mode -
// the `infcx` may be re-used between intercrate in non-intercrate // the `infcx` may be re-used between intercrate in non-intercrate
@ -907,15 +912,15 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
debug!("opt_normalize_projection_type: found error"); debug!("opt_normalize_projection_type: found error");
let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth); let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth);
obligations.extend(result.obligations); obligations.extend(result.obligations);
return Ok(Some(result.value)); return Ok(Some(result.value.into()));
} }
} }
let obligation = Obligation::with_depth(cause.clone(), depth, param_env, projection_ty); let obligation = Obligation::with_depth(cause.clone(), depth, param_env, projection_ty);
match project_type(selcx, &obligation) { match project(selcx, &obligation) {
Ok(ProjectedTy::Progress(Progress { Ok(Projected::Progress(Progress {
ty: projected_ty, term: projected_term,
obligations: mut projected_obligations, obligations: mut projected_obligations,
})) => { })) => {
// if projection succeeded, then what we get out of this // if projection succeeded, then what we get out of this
@ -923,10 +928,9 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
// an impl, where-clause etc) and hence we must // an impl, where-clause etc) and hence we must
// re-normalize it // re-normalize it
let projected_ty = selcx.infcx().resolve_vars_if_possible(projected_ty); let projected_term = selcx.infcx().resolve_vars_if_possible(projected_term);
debug!(?projected_ty, ?depth, ?projected_obligations);
let mut result = if projected_ty.has_projections() { let mut result = if projected_term.has_projections() {
let mut normalizer = AssocTypeNormalizer::new( let mut normalizer = AssocTypeNormalizer::new(
selcx, selcx,
param_env, param_env,
@ -934,13 +938,11 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
depth + 1, depth + 1,
&mut projected_obligations, &mut projected_obligations,
); );
let normalized_ty = normalizer.fold(projected_ty); let normalized_ty = normalizer.fold(projected_term);
debug!(?normalized_ty, ?depth);
Normalized { value: normalized_ty, obligations: projected_obligations } Normalized { value: normalized_ty, obligations: projected_obligations }
} else { } else {
Normalized { value: projected_ty, obligations: projected_obligations } Normalized { value: projected_term, obligations: projected_obligations }
}; };
let mut deduped: SsoHashSet<_> = Default::default(); let mut deduped: SsoHashSet<_> = Default::default();
@ -952,28 +954,27 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
}); });
if use_cache { if use_cache {
infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone()); infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone());
} }
obligations.extend(result.obligations); obligations.extend(result.obligations);
Ok(Some(result.value)) Ok(Some(result.value.into()))
} }
Ok(ProjectedTy::NoProgress(projected_ty)) => { Ok(Projected::NoProgress(projected_ty)) => {
debug!(?projected_ty, "opt_normalize_projection_type: no progress");
let result = Normalized { value: projected_ty, obligations: vec![] }; let result = Normalized { value: projected_ty, obligations: vec![] };
if use_cache { if use_cache {
infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone()); infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone());
} }
// No need to extend `obligations`. // No need to extend `obligations`.
Ok(Some(result.value)) Ok(Some(result.value))
} }
Err(ProjectionTyError::TooManyCandidates) => { Err(ProjectionError::TooManyCandidates) => {
debug!("opt_normalize_projection_type: too many candidates"); debug!("opt_normalize_projection_type: too many candidates");
if use_cache { if use_cache {
infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key); infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key);
} }
Ok(None) Ok(None)
} }
Err(ProjectionTyError::TraitSelectionError(_)) => { Err(ProjectionError::TraitSelectionError(_)) => {
debug!("opt_normalize_projection_type: ERROR"); debug!("opt_normalize_projection_type: ERROR");
// if we got an error processing the `T as Trait` part, // if we got an error processing the `T as Trait` part,
// just return `ty::err` but add the obligation `T : // just return `ty::err` but add the obligation `T :
@ -985,7 +986,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
} }
let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth); let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth);
obligations.extend(result.obligations); obligations.extend(result.obligations);
Ok(Some(result.value)) Ok(Some(result.value.into()))
} }
} }
} }
@ -1032,30 +1033,22 @@ fn normalize_to_error<'a, 'tcx>(
Normalized { value: new_value, obligations: vec![trait_obligation] } Normalized { value: new_value, obligations: vec![trait_obligation] }
} }
enum ProjectedTy<'tcx> { enum Projected<'tcx> {
Progress(Progress<'tcx>), Progress(Progress<'tcx>),
NoProgress(Ty<'tcx>), NoProgress(ty::Term<'tcx>),
} }
struct Progress<'tcx> { struct Progress<'tcx> {
ty: Ty<'tcx>, term: ty::Term<'tcx>,
obligations: Vec<PredicateObligation<'tcx>>, obligations: Vec<PredicateObligation<'tcx>>,
} }
impl<'tcx> Progress<'tcx> { impl<'tcx> Progress<'tcx> {
fn error(tcx: TyCtxt<'tcx>) -> Self { fn error(tcx: TyCtxt<'tcx>) -> Self {
Progress { ty: tcx.ty_error(), obligations: vec![] } Progress { term: tcx.ty_error().into(), obligations: vec![] }
} }
fn with_addl_obligations(mut self, mut obligations: Vec<PredicateObligation<'tcx>>) -> Self { fn with_addl_obligations(mut self, mut obligations: Vec<PredicateObligation<'tcx>>) -> Self {
debug!(
self.obligations.len = ?self.obligations.len(),
obligations.len = obligations.len(),
"with_addl_obligations"
);
debug!(?self.obligations, ?obligations, "with_addl_obligations");
self.obligations.append(&mut obligations); self.obligations.append(&mut obligations);
self self
} }
@ -1066,22 +1059,21 @@ impl<'tcx> Progress<'tcx> {
/// IMPORTANT: /// IMPORTANT:
/// - `obligation` must be fully normalized /// - `obligation` must be fully normalized
#[tracing::instrument(level = "info", skip(selcx))] #[tracing::instrument(level = "info", skip(selcx))]
fn project_type<'cx, 'tcx>( fn project<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>, selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>, obligation: &ProjectionTyObligation<'tcx>,
) -> Result<ProjectedTy<'tcx>, ProjectionTyError<'tcx>> { ) -> Result<Projected<'tcx>, ProjectionError<'tcx>> {
if !selcx.tcx().recursion_limit().value_within_limit(obligation.recursion_depth) { if !selcx.tcx().recursion_limit().value_within_limit(obligation.recursion_depth) {
debug!("project: overflow!");
// This should really be an immediate error, but some existing code // This should really be an immediate error, but some existing code
// relies on being able to recover from this. // relies on being able to recover from this.
return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow)); return Err(ProjectionError::TraitSelectionError(SelectionError::Overflow));
} }
if obligation.predicate.references_error() { if obligation.predicate.references_error() {
return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx()))); return Ok(Projected::Progress(Progress::error(selcx.tcx())));
} }
let mut candidates = ProjectionTyCandidateSet::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
// needs to be first because it has highest priority, and Select checks // needs to be first because it has highest priority, and Select checks
@ -1092,7 +1084,7 @@ fn project_type<'cx, 'tcx>(
assemble_candidates_from_object_ty(selcx, obligation, &mut candidates); assemble_candidates_from_object_ty(selcx, obligation, &mut candidates);
if let ProjectionTyCandidateSet::Single(ProjectionTyCandidate::Object(_)) = candidates { if let ProjectionCandidateSet::Single(ProjectionCandidate::Object(_)) = candidates {
// Avoid normalization cycle from selection (see // Avoid normalization cycle from selection (see
// `assemble_candidates_from_object_ty`). // `assemble_candidates_from_object_ty`).
// FIXME(lazy_normalization): Lazy normalization should save us from // FIXME(lazy_normalization): Lazy normalization should save us from
@ -1102,19 +1094,22 @@ fn project_type<'cx, 'tcx>(
}; };
match candidates { match candidates {
ProjectionTyCandidateSet::Single(candidate) => { ProjectionCandidateSet::Single(candidate) => {
Ok(ProjectedTy::Progress(confirm_candidate(selcx, obligation, candidate))) Ok(Projected::Progress(confirm_candidate(selcx, obligation, candidate)))
} }
ProjectionTyCandidateSet::None => Ok(ProjectedTy::NoProgress( ProjectionCandidateSet::None => Ok(Projected::NoProgress(
// FIXME(associated_const_generics): this may need to change in the future?
// need to investigate whether or not this is fine.
selcx selcx
.tcx() .tcx()
.mk_projection(obligation.predicate.item_def_id, obligation.predicate.substs), .mk_projection(obligation.predicate.item_def_id, obligation.predicate.substs)
.into(),
)), )),
// Error occurred while trying to processing impls. // Error occurred while trying to processing impls.
ProjectionTyCandidateSet::Error(e) => Err(ProjectionTyError::TraitSelectionError(e)), ProjectionCandidateSet::Error(e) => Err(ProjectionError::TraitSelectionError(e)),
// Inherent ambiguity that prevents us from even enumerating the // Inherent ambiguity that prevents us from even enumerating the
// candidates. // candidates.
ProjectionTyCandidateSet::Ambiguous => Err(ProjectionTyError::TooManyCandidates), ProjectionCandidateSet::Ambiguous => Err(ProjectionError::TooManyCandidates),
} }
} }
@ -1124,14 +1119,13 @@ fn project_type<'cx, 'tcx>(
fn assemble_candidates_from_param_env<'cx, 'tcx>( fn assemble_candidates_from_param_env<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>, selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>, obligation: &ProjectionTyObligation<'tcx>,
candidate_set: &mut ProjectionTyCandidateSet<'tcx>, candidate_set: &mut ProjectionCandidateSet<'tcx>,
) { ) {
debug!("assemble_candidates_from_param_env(..)");
assemble_candidates_from_predicates( assemble_candidates_from_predicates(
selcx, selcx,
obligation, obligation,
candidate_set, candidate_set,
ProjectionTyCandidate::ParamEnv, ProjectionCandidate::ParamEnv,
obligation.param_env.caller_bounds().iter(), obligation.param_env.caller_bounds().iter(),
false, false,
); );
@ -1150,7 +1144,7 @@ fn assemble_candidates_from_param_env<'cx, 'tcx>(
fn assemble_candidates_from_trait_def<'cx, 'tcx>( fn assemble_candidates_from_trait_def<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>, selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>, obligation: &ProjectionTyObligation<'tcx>,
candidate_set: &mut ProjectionTyCandidateSet<'tcx>, candidate_set: &mut ProjectionCandidateSet<'tcx>,
) { ) {
debug!("assemble_candidates_from_trait_def(..)"); debug!("assemble_candidates_from_trait_def(..)");
@ -1173,7 +1167,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
selcx, selcx,
obligation, obligation,
candidate_set, candidate_set,
ProjectionTyCandidate::TraitDef, ProjectionCandidate::TraitDef,
bounds.iter(), bounds.iter(),
true, true,
) )
@ -1191,7 +1185,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
fn assemble_candidates_from_object_ty<'cx, 'tcx>( fn assemble_candidates_from_object_ty<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>, selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>, obligation: &ProjectionTyObligation<'tcx>,
candidate_set: &mut ProjectionTyCandidateSet<'tcx>, candidate_set: &mut ProjectionCandidateSet<'tcx>,
) { ) {
debug!("assemble_candidates_from_object_ty(..)"); debug!("assemble_candidates_from_object_ty(..)");
@ -1218,7 +1212,7 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
selcx, selcx,
obligation, obligation,
candidate_set, candidate_set,
ProjectionTyCandidate::Object, ProjectionCandidate::Object,
env_predicates, env_predicates,
false, false,
); );
@ -1231,14 +1225,13 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
fn assemble_candidates_from_predicates<'cx, 'tcx>( fn assemble_candidates_from_predicates<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>, selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>, obligation: &ProjectionTyObligation<'tcx>,
candidate_set: &mut ProjectionTyCandidateSet<'tcx>, candidate_set: &mut ProjectionCandidateSet<'tcx>,
ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>, ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionCandidate<'tcx>,
env_predicates: impl Iterator<Item = ty::Predicate<'tcx>>, env_predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
potentially_unnormalized_candidates: bool, potentially_unnormalized_candidates: bool,
) { ) {
let infcx = selcx.infcx(); let infcx = selcx.infcx();
for predicate in env_predicates { for predicate in env_predicates {
debug!(?predicate);
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);
@ -1253,8 +1246,6 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
) )
}); });
debug!(?data, ?is_match, ?same_def_id);
if is_match { if is_match {
candidate_set.push_candidate(ctor(data)); candidate_set.push_candidate(ctor(data));
@ -1275,7 +1266,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
fn assemble_candidates_from_impls<'cx, 'tcx>( fn assemble_candidates_from_impls<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>, selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>, obligation: &ProjectionTyObligation<'tcx>,
candidate_set: &mut ProjectionTyCandidateSet<'tcx>, candidate_set: &mut ProjectionCandidateSet<'tcx>,
) { ) {
// If we are resolving `<T as TraitRef<...>>::Item == Type`, // If we are resolving `<T as TraitRef<...>>::Item == Type`,
// start out by selecting the predicate `T as TraitRef<...>`: // start out by selecting the predicate `T as TraitRef<...>`:
@ -1299,10 +1290,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
super::ImplSource::Closure(_) super::ImplSource::Closure(_)
| super::ImplSource::Generator(_) | super::ImplSource::Generator(_)
| super::ImplSource::FnPointer(_) | super::ImplSource::FnPointer(_)
| super::ImplSource::TraitAlias(_) => { | super::ImplSource::TraitAlias(_) => true,
debug!(?impl_source);
true
}
super::ImplSource::UserDefined(impl_data) => { super::ImplSource::UserDefined(impl_data) => {
// We have to be careful when projecting out of an // We have to be careful when projecting out of an
// impl because of specialization. If we are not in // impl because of specialization. If we are not in
@ -1327,7 +1315,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
// NOTE: This should be kept in sync with the similar code in // NOTE: This should be kept in sync with the similar code in
// `rustc_ty_utils::instance::resolve_associated_item()`. // `rustc_ty_utils::instance::resolve_associated_item()`.
let node_item = let node_item =
assoc_ty_def(selcx, impl_data.impl_def_id, obligation.predicate.item_def_id) assoc_def(selcx, impl_data.impl_def_id, obligation.predicate.item_def_id)
.map_err(|ErrorReported| ())?; .map_err(|ErrorReported| ())?;
if node_item.is_final() { if node_item.is_final() {
@ -1500,7 +1488,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
}; };
if eligible { if eligible {
if candidate_set.push_candidate(ProjectionTyCandidate::Select(impl_source)) { if candidate_set.push_candidate(ProjectionCandidate::Select(impl_source)) {
Ok(()) Ok(())
} else { } else {
Err(()) Err(())
@ -1514,30 +1502,32 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
fn confirm_candidate<'cx, 'tcx>( fn confirm_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>, selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>, obligation: &ProjectionTyObligation<'tcx>,
candidate: ProjectionTyCandidate<'tcx>, candidate: ProjectionCandidate<'tcx>,
) -> Progress<'tcx> { ) -> Progress<'tcx> {
debug!(?obligation, ?candidate, "confirm_candidate"); debug!(?obligation, ?candidate, "confirm_candidate");
let mut progress = match candidate { let mut progress = match candidate {
ProjectionTyCandidate::ParamEnv(poly_projection) ProjectionCandidate::ParamEnv(poly_projection)
| ProjectionTyCandidate::Object(poly_projection) => { | ProjectionCandidate::Object(poly_projection) => {
confirm_param_env_candidate(selcx, obligation, poly_projection, false) confirm_param_env_candidate(selcx, obligation, poly_projection, false)
} }
ProjectionTyCandidate::TraitDef(poly_projection) => { ProjectionCandidate::TraitDef(poly_projection) => {
confirm_param_env_candidate(selcx, obligation, poly_projection, true) confirm_param_env_candidate(selcx, obligation, poly_projection, true)
} }
ProjectionTyCandidate::Select(impl_source) => { ProjectionCandidate::Select(impl_source) => {
confirm_select_candidate(selcx, obligation, impl_source) confirm_select_candidate(selcx, obligation, impl_source)
} }
}; };
// When checking for cycle during evaluation, we compare predicates with // When checking for cycle during evaluation, we compare predicates with
// "syntactic" equality. Since normalization generally introduces a type // "syntactic" equality. Since normalization generally introduces a type
// with new region variables, we need to resolve them to existing variables // with new region variables, we need to resolve them to existing variables
// when possible for this to work. See `auto-trait-projection-recursion.rs` // when possible for this to work. See `auto-trait-projection-recursion.rs`
// for a case where this matters. // for a case where this matters.
if progress.ty.has_infer_regions() { if progress.term.has_infer_regions() {
progress.ty = OpportunisticRegionResolver::new(selcx.infcx()).fold_ty(progress.ty); progress.term =
progress.term.fold_with(&mut OpportunisticRegionResolver::new(selcx.infcx()));
} }
progress progress
} }
@ -1804,7 +1794,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations); assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations);
// FIXME(associated_const_equality): Handle consts here as well? Maybe this progress type should just take // FIXME(associated_const_equality): Handle consts here as well? Maybe this progress type should just take
// a term instead. // a term instead.
Progress { ty: cache_entry.term.ty().unwrap(), obligations: nested_obligations } Progress { term: cache_entry.term, obligations: nested_obligations }
} }
Err(e) => { Err(e) => {
let msg = format!( let msg = format!(
@ -1813,7 +1803,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
); );
debug!("confirm_param_env_candidate: {}", msg); debug!("confirm_param_env_candidate: {}", msg);
let err = infcx.tcx.ty_error_with_message(obligation.cause.span, &msg); let err = infcx.tcx.ty_error_with_message(obligation.cause.span, &msg);
Progress { ty: err, obligations: vec![] } Progress { term: err.into(), obligations: vec![] }
} }
} }
} }
@ -1830,9 +1820,9 @@ fn confirm_impl_candidate<'cx, 'tcx>(
let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap(); let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
let param_env = obligation.param_env; let param_env = obligation.param_env;
let assoc_ty = match assoc_ty_def(selcx, impl_def_id, assoc_item_id) { let assoc_ty = match assoc_def(selcx, impl_def_id, assoc_item_id) {
Ok(assoc_ty) => assoc_ty, Ok(assoc_ty) => assoc_ty,
Err(ErrorReported) => return Progress { ty: tcx.ty_error(), obligations: nested }, Err(ErrorReported) => return Progress { term: tcx.ty_error().into(), obligations: nested },
}; };
if !assoc_ty.item.defaultness.has_value() { if !assoc_ty.item.defaultness.has_value() {
@ -1844,7 +1834,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
"confirm_impl_candidate: no associated type {:?} for {:?}", "confirm_impl_candidate: no associated type {:?} for {:?}",
assoc_ty.item.name, obligation.predicate assoc_ty.item.name, obligation.predicate
); );
return Progress { ty: tcx.ty_error(), obligations: nested }; return Progress { term: tcx.ty_error().into(), obligations: nested };
} }
// If we're trying to normalize `<Vec<u32> as X>::A<S>` using // If we're trying to normalize `<Vec<u32> as X>::A<S>` using
//`impl<T> X for Vec<T> { type A<Y> = Box<Y>; }`, then: //`impl<T> X for Vec<T> { type A<Y> = Box<Y>; }`, then:
@ -1856,15 +1846,25 @@ fn confirm_impl_candidate<'cx, 'tcx>(
let substs = let substs =
translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.defining_node); translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.defining_node);
let ty = tcx.type_of(assoc_ty.item.def_id); let ty = tcx.type_of(assoc_ty.item.def_id);
let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst);
let term: ty::Term<'tcx> = if is_const {
let identity_substs =
crate::traits::InternalSubsts::identity_for_item(tcx, assoc_ty.item.def_id);
let did = ty::WithOptConstParam::unknown(assoc_ty.item.def_id);
let val = ty::ConstKind::Unevaluated(ty::Unevaluated::new(did, identity_substs));
tcx.mk_const(ty::Const { ty, val }).into()
} else {
ty.into()
};
if substs.len() != tcx.generics_of(assoc_ty.item.def_id).count() { if substs.len() != tcx.generics_of(assoc_ty.item.def_id).count() {
let err = tcx.ty_error_with_message( let err = tcx.ty_error_with_message(
obligation.cause.span, obligation.cause.span,
"impl item and trait item have different parameter counts", "impl item and trait item have different parameter counts",
); );
Progress { ty: err, obligations: nested } Progress { term: err.into(), obligations: nested }
} else { } else {
assoc_ty_own_obligations(selcx, obligation, &mut nested); assoc_ty_own_obligations(selcx, obligation, &mut nested);
Progress { ty: ty.subst(tcx, substs), obligations: nested } Progress { term: term.subst(tcx, substs), obligations: nested }
} }
} }
@ -1905,10 +1905,10 @@ fn assoc_ty_own_obligations<'cx, 'tcx>(
/// ///
/// Based on the "projection mode", this lookup may in fact only examine the /// Based on the "projection mode", this lookup may in fact only examine the
/// topmost impl. See the comments for `Reveal` for more details. /// topmost impl. See the comments for `Reveal` for more details.
fn assoc_ty_def( fn assoc_def(
selcx: &SelectionContext<'_, '_>, selcx: &SelectionContext<'_, '_>,
impl_def_id: DefId, impl_def_id: DefId,
assoc_ty_def_id: DefId, assoc_def_id: DefId,
) -> Result<specialization_graph::LeafDef, ErrorReported> { ) -> Result<specialization_graph::LeafDef, ErrorReported> {
let tcx = selcx.tcx(); let tcx = selcx.tcx();
let trait_def_id = tcx.impl_trait_ref(impl_def_id).unwrap().def_id; let trait_def_id = tcx.impl_trait_ref(impl_def_id).unwrap().def_id;
@ -1920,7 +1920,7 @@ fn assoc_ty_def(
// for the associated item at the given impl. // for the associated item at the given impl.
// If there is no such item in that impl, this function will fail with a // If there is no such item in that impl, this function will fail with a
// cycle error if the specialization graph is currently being built. // cycle error if the specialization graph is currently being built.
if let Some(&impl_item_id) = tcx.impl_item_implementor_ids(impl_def_id).get(&assoc_ty_def_id) { if let Some(&impl_item_id) = tcx.impl_item_implementor_ids(impl_def_id).get(&assoc_def_id) {
let item = tcx.associated_item(impl_item_id); let item = tcx.associated_item(impl_item_id);
let impl_node = specialization_graph::Node::Impl(impl_def_id); let impl_node = specialization_graph::Node::Impl(impl_def_id);
return Ok(specialization_graph::LeafDef { return Ok(specialization_graph::LeafDef {
@ -1931,7 +1931,7 @@ fn assoc_ty_def(
} }
let ancestors = trait_def.ancestors(tcx, impl_def_id)?; let ancestors = trait_def.ancestors(tcx, impl_def_id)?;
if let Some(assoc_item) = ancestors.leaf_def(tcx, assoc_ty_def_id) { if let Some(assoc_item) = ancestors.leaf_def(tcx, assoc_def_id) {
Ok(assoc_item) Ok(assoc_item)
} else { } else {
// This is saying that neither the trait nor // This is saying that neither the trait nor
@ -1942,7 +1942,7 @@ fn assoc_ty_def(
// should have failed in astconv. // should have failed in astconv.
bug!( bug!(
"No associated type `{}` for {}", "No associated type `{}` for {}",
tcx.item_name(assoc_ty_def_id), tcx.item_name(assoc_def_id),
tcx.def_path_str(impl_def_id) tcx.def_path_str(impl_def_id)
) )
} }

View File

@ -36,7 +36,10 @@ fn normalize_projection_ty<'tcx>(
&mut obligations, &mut obligations,
); );
fulfill_cx.register_predicate_obligations(infcx, obligations); fulfill_cx.register_predicate_obligations(infcx, obligations);
Ok(NormalizationResult { normalized_ty: answer }) // FIXME(associated_const_equality): All users of normalize_projection_ty expected
// a type, but there is the possibility it could've been a const now. Maybe change
// it to a Term later?
Ok(NormalizationResult { normalized_ty: answer.ty().unwrap() })
}, },
) )
} }

View File

@ -1145,7 +1145,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
// of calling `filter_by_name_and_kind`. // of calling `filter_by_name_and_kind`.
let assoc_ty = tcx let assoc_item = tcx
.associated_items(candidate.def_id()) .associated_items(candidate.def_id())
.filter_by_name_unhygienic(assoc_ident.name) .filter_by_name_unhygienic(assoc_ident.name)
.find(|i| { .find(|i| {
@ -1153,35 +1153,32 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
&& i.ident(tcx).normalize_to_macros_2_0() == assoc_ident && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
}) })
.expect("missing associated type"); .expect("missing associated type");
// FIXME(associated_const_equality): need to handle assoc_consts here as well.
if assoc_ty.kind == ty::AssocKind::Const {
tcx.sess
.struct_span_err(path_span, &format!("associated const equality is incomplete"))
.span_label(path_span, "cannot yet relate associated const")
.emit();
return Err(ErrorReported);
}
if !assoc_ty.vis.is_accessible_from(def_scope, tcx) { if !assoc_item.vis.is_accessible_from(def_scope, tcx) {
let kind = match assoc_item.kind {
ty::AssocKind::Type => "type",
ty::AssocKind::Const => "const",
_ => unreachable!(),
};
tcx.sess tcx.sess
.struct_span_err( .struct_span_err(
binding.span, binding.span,
&format!("associated type `{}` is private", binding.item_name), &format!("associated {kind} `{}` is private", binding.item_name),
) )
.span_label(binding.span, "private associated type") .span_label(binding.span, &format!("private associated {kind}"))
.emit(); .emit();
} }
tcx.check_stability(assoc_ty.def_id, Some(hir_ref_id), binding.span, None); tcx.check_stability(assoc_item.def_id, Some(hir_ref_id), binding.span, None);
if !speculative { if !speculative {
dup_bindings dup_bindings
.entry(assoc_ty.def_id) .entry(assoc_item.def_id)
.and_modify(|prev_span| { .and_modify(|prev_span| {
self.tcx().sess.emit_err(ValueOfAssociatedStructAlreadySpecified { self.tcx().sess.emit_err(ValueOfAssociatedStructAlreadySpecified {
span: binding.span, span: binding.span,
prev_span: *prev_span, prev_span: *prev_span,
item_name: binding.item_name, item_name: binding.item_name,
def_path: tcx.def_path_str(assoc_ty.container.id()), def_path: tcx.def_path_str(assoc_item.container.id()),
}); });
}) })
.or_insert(binding.span); .or_insert(binding.span);
@ -1189,7 +1186,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// Include substitutions for generic parameters of associated types // Include substitutions for generic parameters of associated types
let projection_ty = candidate.map_bound(|trait_ref| { let projection_ty = candidate.map_bound(|trait_ref| {
let ident = Ident::new(assoc_ty.name, binding.item_name.span); let ident = Ident::new(assoc_item.name, binding.item_name.span);
let item_segment = hir::PathSegment { let item_segment = hir::PathSegment {
ident, ident,
hir_id: Some(binding.hir_id), hir_id: Some(binding.hir_id),
@ -1201,7 +1198,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let substs_trait_ref_and_assoc_item = self.create_substs_for_associated_item( let substs_trait_ref_and_assoc_item = self.create_substs_for_associated_item(
tcx, tcx,
path_span, path_span,
assoc_ty.def_id, assoc_item.def_id,
&item_segment, &item_segment,
trait_ref.substs, trait_ref.substs,
); );
@ -1212,14 +1209,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
); );
ty::ProjectionTy { ty::ProjectionTy {
item_def_id: assoc_ty.def_id, item_def_id: assoc_item.def_id,
substs: substs_trait_ref_and_assoc_item, substs: substs_trait_ref_and_assoc_item,
} }
}); });
if !speculative { if !speculative {
// Find any late-bound regions declared in `ty` that are not // Find any late-bound regions declared in `ty` that are not
// declared in the trait-ref or assoc_ty. These are not well-formed. // declared in the trait-ref or assoc_item. These are not well-formed.
// //
// Example: // Example:
// //
@ -1260,6 +1257,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// the "projection predicate" for: // the "projection predicate" for:
// //
// `<T as Iterator>::Item = u32` // `<T as Iterator>::Item = u32`
let assoc_item_def_id = projection_ty.skip_binder().item_def_id;
let def_kind = tcx.def_kind(assoc_item_def_id);
match (def_kind, term) {
(hir::def::DefKind::AssocTy, ty::Term::Ty(_))
| (hir::def::DefKind::AssocConst, ty::Term::Const(_)) => (),
(_, _) => {
let got = if let ty::Term::Ty(_) = term { "type" } else { "const" };
let expected = def_kind.descr(assoc_item_def_id);
tcx.sess
.struct_span_err(
binding.span,
&format!("mismatch in bind of {expected}, got {got}"),
)
.span_note(
tcx.def_span(assoc_item_def_id),
&format!("{expected} defined here does not match {got}"),
)
.emit();
}
}
bounds.projection_bounds.push(( bounds.projection_bounds.push((
projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate { projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
projection_ty, projection_ty,

View File

@ -1,5 +1,6 @@
use rustc_errors::{Applicability, ErrorReported, StashKey}; use rustc_errors::{Applicability, ErrorReported, StashKey};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::CtorOf;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit; use rustc_hir::intravisit;
@ -160,21 +161,36 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
// We've encountered an `AnonConst` in some path, so we need to // We've encountered an `AnonConst` in some path, so we need to
// figure out which generic parameter it corresponds to and return // figure out which generic parameter it corresponds to and return
// the relevant type. // the relevant type.
let filtered = path let filtered = path.segments.iter().find_map(|seg| {
.segments seg.args?
.iter() .args
.filter_map(|seg| seg.args.map(|args| (args.args, seg))) .iter()
.find_map(|(args, seg)| { .filter(|arg| arg.is_ty_or_const())
args.iter() .position(|arg| arg.id() == hir_id)
.filter(|arg| arg.is_ty_or_const()) .map(|index| (index, seg))
.position(|arg| arg.id() == hir_id) });
.map(|index| (index, seg))
}); // FIXME(associated_const_generics): can we blend this with iteration above?
let (arg_index, segment) = match filtered { let (arg_index, segment) = match filtered {
None => { None => {
tcx.sess let binding_filtered = path.segments.iter().find_map(|seg| {
.delay_span_bug(tcx.def_span(def_id), "no arg matching AnonConst in path"); seg.args?
return None; .bindings
.iter()
.filter_map(TypeBinding::opt_const)
.position(|ct| ct.hir_id == hir_id)
.map(|idx| (idx, seg))
});
match binding_filtered {
Some(inner) => inner,
None => {
tcx.sess.delay_span_bug(
tcx.def_span(def_id),
"no arg matching AnonConst in path",
);
return None;
}
}
} }
Some(inner) => inner, Some(inner) => inner,
}; };
@ -182,7 +198,6 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
// Try to use the segment resolution if it is valid, otherwise we // Try to use the segment resolution if it is valid, otherwise we
// default to the path resolution. // default to the path resolution.
let res = segment.res.filter(|&r| r != Res::Err).unwrap_or(path.res); let res = segment.res.filter(|&r| r != Res::Err).unwrap_or(path.res);
use def::CtorOf;
let generics = match res { let generics = match res {
Res::Def(DefKind::Ctor(CtorOf::Variant, _), def_id) => tcx Res::Def(DefKind::Ctor(CtorOf::Variant, _), def_id) => tcx
.generics_of(tcx.parent(def_id).and_then(|def_id| tcx.parent(def_id)).unwrap()), .generics_of(tcx.parent(def_id).and_then(|def_id| tcx.parent(def_id)).unwrap()),
@ -483,15 +498,49 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
.discr_type() .discr_type()
.to_ty(tcx), .to_ty(tcx),
Node::TraitRef(trait_ref @ &TraitRef {
path, ..
}) if let Some((binding, seg)) =
path
.segments
.iter()
.find_map(|seg| {
seg.args?.bindings
.iter()
.find_map(|binding| if binding.opt_const()?.hir_id == hir_id {
Some((binding, seg))
} else {
None
})
}) =>
{
// FIXME(associated_const_equality) when does this unwrap fail? I have no idea what case it would.
let trait_def_id = trait_ref.trait_def_id().unwrap();
let assoc_items = tcx.associated_items(trait_def_id);
let assoc_item = assoc_items.find_by_name_and_kind(
tcx, binding.ident, ty::AssocKind::Const, def_id.to_def_id(),
);
if let Some(assoc_item) = assoc_item {
tcx.type_of(assoc_item.def_id)
} else {
// FIXME(associated_const_equality): add a useful error message here.
tcx.ty_error_with_message(
DUMMY_SP,
&format!("Could not find associated const on trait"),
)
}
}
Node::GenericParam(&GenericParam { Node::GenericParam(&GenericParam {
hir_id: param_hir_id, hir_id: param_hir_id,
kind: GenericParamKind::Const { default: Some(ct), .. }, kind: GenericParamKind::Const { default: Some(ct), .. },
.. ..
}) if ct.hir_id == hir_id => tcx.type_of(tcx.hir().local_def_id(param_hir_id)), }) if ct.hir_id == hir_id => tcx.type_of(tcx.hir().local_def_id(param_hir_id)),
x => tcx.ty_error_with_message( x =>
tcx.ty_error_with_message(
DUMMY_SP, DUMMY_SP,
&format!("unexpected const parent in type_of(): {:?}", x), &format!("unexpected const parent in type_of(): {x:?}"),
), ),
} }
} }

View File

@ -0,0 +1,26 @@
#![feature(associated_const_equality)]
#![allow(unused)]
pub trait Foo {
const N: usize;
}
pub struct Bar;
impl Foo for Bar {
const N: usize = 3;
}
fn foo1<F: Foo<Z=3>>() {}
//~^ ERROR associated type
fn foo2<F: Foo<Z=usize>>() {}
//~^ ERROR associated type
fn foo3<F: Foo<Z=5>>() {}
//~^ ERROR associated type
fn main() {
foo1::<Bar>();
foo2::<Bar>();
foo3::<Bar>();
}

View File

@ -0,0 +1,21 @@
error[E0220]: associated type `Z` not found for `Foo`
--> $DIR/assoc-const-eq-missing.rs:15:16
|
LL | fn foo1<F: Foo<Z=3>>() {}
| ^ associated type `Z` not found
error[E0220]: associated type `Z` not found for `Foo`
--> $DIR/assoc-const-eq-missing.rs:17:16
|
LL | fn foo2<F: Foo<Z=usize>>() {}
| ^ associated type `Z` not found
error[E0220]: associated type `Z` not found for `Foo`
--> $DIR/assoc-const-eq-missing.rs:19:16
|
LL | fn foo3<F: Foo<Z=5>>() {}
| ^ associated type `Z` not found
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0220`.

View File

@ -0,0 +1,31 @@
#![feature(associated_const_equality)]
#![allow(unused)]
pub trait Foo {
const N: usize;
}
pub trait FooTy {
type T;
}
pub struct Bar;
impl Foo for Bar {
const N: usize = 3;
}
impl FooTy for Bar {
type T = usize;
}
fn foo<F: Foo<N=usize>>() {}
//~^ ERROR mismatch in
fn foo2<F: FooTy<T=3usize>>() {}
//~^ ERROR mismatch in
fn main() {
foo::<Bar>();
foo2::<Bar>();
}

View File

@ -0,0 +1,26 @@
error: mismatch in bind of associated constant, got type
--> $DIR/assoc-const-ty-mismatch.rs:23:15
|
LL | fn foo<F: Foo<N=usize>>() {}
| ^^^^^^^
|
note: associated constant defined here does not match type
--> $DIR/assoc-const-ty-mismatch.rs:5:3
|
LL | const N: usize;
| ^^^^^^^^^^^^^^^
error: mismatch in bind of associated type, got const
--> $DIR/assoc-const-ty-mismatch.rs:25:18
|
LL | fn foo2<F: FooTy<T=3usize>>() {}
| ^^^^^^^^
|
note: associated type defined here does not match const
--> $DIR/assoc-const-ty-mismatch.rs:9:3
|
LL | type T;
| ^^^^^^^
error: aborting due to 2 previous errors

View File

@ -1,4 +1,6 @@
// run-pass
#![feature(associated_const_equality)] #![feature(associated_const_equality)]
#![allow(unused)]
pub trait Foo { pub trait Foo {
const N: usize; const N: usize;
@ -13,9 +15,8 @@ impl Foo for Bar {
const TEST:usize = 3; const TEST:usize = 3;
fn foo<F: Foo<N=3>>() {} fn foo<F: Foo<N=3usize>>() {}
//~^ ERROR associated const equality is incomplete
fn bar<F: Foo<N={TEST}>>() {}
//~^ ERROR associated const equality is incomplete
fn main() {} fn main() {
foo::<Bar>()
}

View File

@ -1,14 +0,0 @@
error: associated const equality is incomplete
--> $DIR/assoc-const.rs:16:15
|
LL | fn foo<F: Foo<N=3>>() {}
| ^^^ cannot yet relate associated const
error: associated const equality is incomplete
--> $DIR/assoc-const.rs:18:15
|
LL | fn bar<F: Foo<N={TEST}>>() {}
| ^^^^^^^^ cannot yet relate associated const
error: aborting due to 2 previous errors

View File

@ -9,7 +9,6 @@ impl TraitWAssocConst for Demo {
fn foo<A: TraitWAssocConst<A=32>>() {} fn foo<A: TraitWAssocConst<A=32>>() {}
//~^ ERROR associated const equality //~^ ERROR associated const equality
//~| ERROR associated const equality
fn main() { fn main() {
foo::<Demo>(); foo::<Demo>();

View File

@ -7,12 +7,6 @@ LL | fn foo<A: TraitWAssocConst<A=32>>() {}
= note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
error: associated const equality is incomplete error: aborting due to previous error
--> $DIR/feature-gate-associated_const_equality.rs:10:28
|
LL | fn foo<A: TraitWAssocConst<A=32>>() {}
| ^^^^ cannot yet relate associated const
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`. For more information about this error, try `rustc --explain E0658`.