summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_trait_selection/src/traits/project.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
commit4547b622d8d29df964fa2914213088b148c498fc (patch)
tree9fc6b25f3c3add6b745be9a2400a6e96140046e9 /compiler/rustc_trait_selection/src/traits/project.rs
parentReleasing progress-linux version 1.66.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-4547b622d8d29df964fa2914213088b148c498fc.tar.xz
rustc-4547b622d8d29df964fa2914213088b148c498fc.zip
Merging upstream version 1.67.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits/project.rs')
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs577
1 files changed, 309 insertions, 268 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index e4284b9d3..5789754e4 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -11,8 +11,8 @@ use super::Selection;
use super::SelectionContext;
use super::SelectionError;
use super::{
- ImplSourceClosureData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData,
- ImplSourceGeneratorData, ImplSourcePointeeData, ImplSourceUserDefinedData,
+ ImplSourceClosureData, ImplSourceFnPointerData, ImplSourceFutureData, ImplSourceGeneratorData,
+ ImplSourceUserDefinedData,
};
use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
@@ -27,7 +27,9 @@ use rustc_errors::ErrorGuaranteed;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
+use rustc_infer::infer::at::At;
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
+use rustc_infer::traits::ImplSourceBuiltinData;
use rustc_middle::traits::select::OverflowError;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable};
@@ -47,6 +49,23 @@ pub type ProjectionTyObligation<'tcx> = Obligation<'tcx, ty::ProjectionTy<'tcx>>
pub(super) struct InProgress;
+pub trait NormalizeExt<'tcx> {
+ /// Normalize a value using the `AssocTypeNormalizer`.
+ ///
+ /// This normalization should be used when the type contains inference variables or the
+ /// projection may be fallible.
+ fn normalize<T: TypeFoldable<'tcx>>(&self, t: T) -> InferOk<'tcx, T>;
+}
+
+impl<'tcx> NormalizeExt<'tcx> for At<'_, 'tcx> {
+ fn normalize<T: TypeFoldable<'tcx>>(&self, value: T) -> InferOk<'tcx, T> {
+ let mut selcx = SelectionContext::new(self.infcx);
+ let Normalized { value, obligations } =
+ normalize_with_depth(&mut selcx, self.param_env, self.cause.clone(), 0, value);
+ InferOk { value, obligations }
+ }
+}
+
/// When attempting to resolve `<T as TraitRef>::Name` ...
#[derive(Debug)]
pub enum ProjectionError<'tcx> {
@@ -193,14 +212,14 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &PolyProjectionObligation<'tcx>,
) -> ProjectAndUnifyResult<'tcx> {
- let infcx = selcx.infcx();
+ let infcx = selcx.infcx;
let r = infcx.commit_if_ok(|_snapshot| {
let old_universe = infcx.universe();
let placeholder_predicate =
infcx.replace_bound_vars_with_placeholders(obligation.predicate);
let new_universe = infcx.universe();
- let placeholder_obligation = obligation.with(placeholder_predicate);
+ let placeholder_obligation = obligation.with(infcx.tcx, placeholder_predicate);
match project_and_unify_type(selcx, &placeholder_obligation) {
ProjectAndUnifyResult::MismatchedProjectionTypes(e) => Err(e),
ProjectAndUnifyResult::Holds(obligations)
@@ -249,7 +268,7 @@ fn project_and_unify_type<'cx, 'tcx>(
) -> ProjectAndUnifyResult<'tcx> {
let mut obligations = vec![];
- let infcx = selcx.infcx();
+ let infcx = selcx.infcx;
let normalized = match opt_normalize_projection_type(
selcx,
obligation.param_env,
@@ -268,7 +287,7 @@ fn project_and_unify_type<'cx, 'tcx>(
// This allows users to omit re-mentioning all bounds on an associated type and just use an
// `impl Trait` for the assoc type to add more bounds.
let InferOk { value: actual, obligations: new } =
- selcx.infcx().replace_opaque_types_with_inference_vars(
+ selcx.infcx.replace_opaque_types_with_inference_vars(
actual,
obligation.cause.body_id,
obligation.cause.span,
@@ -288,39 +307,8 @@ fn project_and_unify_type<'cx, 'tcx>(
}
}
-/// Normalizes any associated type projections in `value`, replacing
-/// them with a fully resolved type where possible. The return value
-/// combines the normalized result and any additional obligations that
-/// were incurred as result.
-pub fn normalize<'a, 'b, 'tcx, T>(
- selcx: &'a mut SelectionContext<'b, 'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- cause: ObligationCause<'tcx>,
- value: T,
-) -> Normalized<'tcx, T>
-where
- T: TypeFoldable<'tcx>,
-{
- let mut obligations = Vec::new();
- let value = normalize_to(selcx, param_env, cause, value, &mut obligations);
- Normalized { value, obligations }
-}
-
-pub fn normalize_to<'a, 'b, 'tcx, T>(
- selcx: &'a mut SelectionContext<'b, 'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- cause: ObligationCause<'tcx>,
- value: T,
- obligations: &mut Vec<PredicateObligation<'tcx>>,
-) -> T
-where
- T: TypeFoldable<'tcx>,
-{
- normalize_with_depth_to(selcx, param_env, cause, 0, value, obligations)
-}
-
/// As `normalize`, but with a custom depth.
-pub fn normalize_with_depth<'a, 'b, 'tcx, T>(
+pub(crate) fn normalize_with_depth<'a, 'b, 'tcx, T>(
selcx: &'a mut SelectionContext<'b, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>,
@@ -336,7 +324,7 @@ where
}
#[instrument(level = "info", skip(selcx, param_env, cause, obligations))]
-pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>(
+pub(crate) fn normalize_with_depth_to<'a, 'b, 'tcx, T>(
selcx: &'a mut SelectionContext<'b, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>,
@@ -356,7 +344,7 @@ where
}
#[instrument(level = "info", skip(selcx, param_env, cause, obligations))]
-pub fn try_normalize_with_depth_to<'a, 'b, 'tcx, T>(
+pub(crate) fn try_normalize_with_depth_to<'a, 'b, 'tcx, T>(
selcx: &'a mut SelectionContext<'b, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>,
@@ -444,7 +432,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
}
fn fold<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
- let value = self.selcx.infcx().resolve_vars_if_possible(value);
+ let value = self.selcx.infcx.resolve_vars_if_possible(value);
debug!(?value);
assert!(
@@ -516,13 +504,12 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
Reveal::All => {
let recursion_limit = self.tcx().recursion_limit();
if !recursion_limit.value_within_limit(self.depth) {
- let obligation = Obligation::with_depth(
- self.cause.clone(),
- recursion_limit.0,
- self.param_env,
- ty,
+ self.selcx.infcx.err_ctxt().report_overflow_error(
+ &ty,
+ self.cause.span,
+ true,
+ |_| {},
);
- self.selcx.infcx().err_ctxt().report_overflow_error(&obligation, true);
}
let substs = substs.fold_with(self);
@@ -588,7 +575,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
// want to figure out how to register obligations with escaping vars
// or handle this some other way.
- let infcx = self.selcx.infcx();
+ let infcx = self.selcx.infcx;
let (data, mapped_regions, mapped_types, mapped_consts) =
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
let data = data.fold_with(self);
@@ -632,13 +619,13 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
#[instrument(skip(self), level = "debug")]
fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> {
let tcx = self.selcx.tcx();
- if tcx.lazy_normalization() {
+ if tcx.lazy_normalization() || !needs_normalization(&constant, self.param_env.reveal()) {
constant
} else {
let constant = constant.super_fold_with(self);
debug!(?constant, ?self.param_env);
with_replaced_escaping_bound_vars(
- self.selcx.infcx(),
+ self.selcx.infcx,
&mut self.universes,
constant,
|constant| constant.eval(tcx, self.param_env),
@@ -816,9 +803,7 @@ impl<'tcx> TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> {
let universe = self.universe_for(debruijn);
let p = ty::PlaceholderConst { universe, name: bound_const };
self.mapped_consts.insert(p, bound_const);
- self.infcx
- .tcx
- .mk_const(ty::ConstS { kind: ty::ConstKind::Placeholder(p), ty: ct.ty() })
+ self.infcx.tcx.mk_const(p, ct.ty())
}
_ => ct.super_fold_with(self),
}
@@ -829,7 +814,7 @@ impl<'tcx> TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> {
}
}
-// The inverse of `BoundVarReplacer`: replaces placeholders with the bound vars from which they came.
+/// The inverse of [`BoundVarReplacer`]: replaces placeholders with the bound vars from which they came.
pub struct PlaceholderReplacer<'me, 'tcx> {
infcx: &'me InferCtxt<'tcx>,
mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
@@ -953,10 +938,7 @@ impl<'tcx> TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> {
let db = ty::DebruijnIndex::from_usize(
self.universe_indices.len() - index + self.current_index.as_usize() - 1,
);
- self.tcx().mk_const(ty::ConstS {
- kind: ty::ConstKind::Bound(db, *replace_var),
- ty: ct.ty(),
- })
+ self.tcx().mk_const(ty::ConstKind::Bound(db, *replace_var), ct.ty())
}
None => ct,
}
@@ -995,10 +977,7 @@ pub fn normalize_projection_type<'a, 'b, 'tcx>(
// and a deferred predicate to resolve this when more type
// information is available.
- selcx
- .infcx()
- .infer_projection(param_env, projection_ty, cause, depth + 1, obligations)
- .into()
+ selcx.infcx.infer_projection(param_env, projection_ty, cause, depth + 1, obligations).into()
})
}
@@ -1021,7 +1000,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
depth: usize,
obligations: &mut Vec<PredicateObligation<'tcx>>,
) -> Result<Option<Term<'tcx>>, InProgress> {
- let infcx = selcx.infcx();
+ let infcx = selcx.infcx;
// Don't use the projection cache in intercrate mode -
// the `infcx` may be re-used between intercrate in non-intercrate
// mode, which could lead to using incorrect cache results.
@@ -1100,7 +1079,8 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
}
}
- let obligation = Obligation::with_depth(cause.clone(), depth, param_env, projection_ty);
+ let obligation =
+ Obligation::with_depth(selcx.tcx(), cause.clone(), depth, param_env, projection_ty);
match project(selcx, &obligation) {
Ok(Projected::Progress(Progress {
@@ -1112,7 +1092,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
// an impl, where-clause etc) and hence we must
// re-normalize it
- let projected_term = selcx.infcx().resolve_vars_if_possible(projected_term);
+ let projected_term = selcx.infcx.resolve_vars_if_possible(projected_term);
let mut result = if projected_term.has_projections() {
let mut normalizer = AssocTypeNormalizer::new(
@@ -1208,9 +1188,9 @@ fn normalize_to_error<'a, 'tcx>(
param_env,
predicate: trait_ref.without_const().to_predicate(selcx.tcx()),
};
- let tcx = selcx.infcx().tcx;
+ let tcx = selcx.infcx.tcx;
let def_id = projection_ty.item_def_id;
- let new_value = selcx.infcx().next_ty_var(TypeVariableOrigin {
+ let new_value = selcx.infcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::NormalizeProjectionType,
span: tcx.def_span(def_id),
});
@@ -1330,11 +1310,10 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>(
obligation.predicate.substs.truncate_to(tcx, tcx.generics_of(trait_def_id));
// FIXME(named-returns): Binders
let trait_predicate =
- ty::Binder::dummy(ty::TraitRef { def_id: trait_def_id, substs: trait_substs })
- .to_poly_trait_predicate();
+ ty::Binder::dummy(ty::TraitRef { def_id: trait_def_id, substs: trait_substs });
- let _ =
- selcx.infcx().commit_if_ok(|_| match selcx.select(&obligation.with(trait_predicate)) {
+ let _ = selcx.infcx.commit_if_ok(|_| {
+ match selcx.select(&obligation.with(tcx, trait_predicate)) {
Ok(Some(super::ImplSource::UserDefined(data))) => {
candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(
ImplTraitInTraitCandidate::Impl(data),
@@ -1354,7 +1333,8 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>(
candidate_set.mark_error(e);
return Err(());
}
- });
+ }
+ });
}
}
@@ -1437,7 +1417,7 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
let tcx = selcx.tcx();
let self_ty = obligation.predicate.self_ty();
- let object_ty = selcx.infcx().shallow_resolve(self_ty);
+ let object_ty = selcx.infcx.shallow_resolve(self_ty);
let data = match object_ty.kind() {
ty::Dynamic(data, ..) => data,
ty::Infer(ty::TyVar(_)) => {
@@ -1475,10 +1455,12 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
env_predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
potentially_unnormalized_candidates: bool,
) {
- let infcx = selcx.infcx();
+ let infcx = selcx.infcx;
for predicate in env_predicates {
let bound_predicate = predicate.kind();
- if let ty::PredicateKind::Projection(data) = predicate.kind().skip_binder() {
+ if let ty::PredicateKind::Clause(ty::Clause::Projection(data)) =
+ predicate.kind().skip_binder()
+ {
let data = bound_predicate.rebind(data);
if data.projection_def_id() != obligation.predicate.item_def_id {
continue;
@@ -1528,8 +1510,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
// If we are resolving `<T as TraitRef<...>>::Item == Type`,
// start out by selecting the predicate `T as TraitRef<...>`:
let poly_trait_ref = ty::Binder::dummy(obligation.predicate.trait_ref(selcx.tcx()));
- let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
- let _ = selcx.infcx().commit_if_ok(|_| {
+ let trait_obligation = obligation.with(selcx.tcx(), poly_trait_ref);
+ let _ = selcx.infcx.commit_if_ok(|_| {
let impl_source = match selcx.select(&trait_obligation) {
Ok(Some(impl_source)) => impl_source,
Ok(None) => {
@@ -1546,6 +1528,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
let eligible = match &impl_source {
super::ImplSource::Closure(_)
| super::ImplSource::Generator(_)
+ | super::ImplSource::Future(_)
| super::ImplSource::FnPointer(_)
| super::ImplSource::TraitAlias(_) => true,
super::ImplSource::UserDefined(impl_data) => {
@@ -1586,7 +1569,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
if obligation.param_env.reveal() == Reveal::All {
// NOTE(eddyb) inference variables can resolve to parameters, so
// assume `poly_trait_ref` isn't monomorphic, if it contains any.
- let poly_trait_ref = selcx.infcx().resolve_vars_if_possible(poly_trait_ref);
+ let poly_trait_ref = selcx.infcx.resolve_vars_if_possible(poly_trait_ref);
!poly_trait_ref.still_further_specializable()
} else {
debug!(
@@ -1598,128 +1581,126 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
}
}
}
- super::ImplSource::DiscriminantKind(..) => {
- // While `DiscriminantKind` is automatically implemented for every type,
- // the concrete discriminant may not be known yet.
- //
- // Any type with multiple potential discriminant types is therefore not eligible.
- let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
-
- match self_ty.kind() {
- ty::Bool
- | ty::Char
- | ty::Int(_)
- | ty::Uint(_)
- | ty::Float(_)
- | ty::Adt(..)
- | ty::Foreign(_)
- | ty::Str
- | ty::Array(..)
- | ty::Slice(_)
- | ty::RawPtr(..)
- | ty::Ref(..)
- | ty::FnDef(..)
- | ty::FnPtr(..)
- | ty::Dynamic(..)
- | ty::Closure(..)
- | ty::Generator(..)
- | ty::GeneratorWitness(..)
- | ty::Never
- | ty::Tuple(..)
- // Integers and floats always have `u8` as their discriminant.
- | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true,
-
- ty::Projection(..)
- | ty::Opaque(..)
- | ty::Param(..)
- | ty::Bound(..)
- | ty::Placeholder(..)
- | ty::Infer(..)
- | ty::Error(_) => false,
- }
- }
- super::ImplSource::Pointee(..) => {
- // While `Pointee` is automatically implemented for every type,
- // the concrete metadata type may not be known yet.
- //
- // Any type with multiple potential metadata types is therefore not eligible.
- let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
-
- let tail = selcx.tcx().struct_tail_with_normalize(
- self_ty,
- |ty| {
- // We throw away any obligations we get from this, since we normalize
- // and confirm these obligations once again during confirmation
- normalize_with_depth(
- selcx,
- obligation.param_env,
- obligation.cause.clone(),
- obligation.recursion_depth + 1,
- ty,
- )
- .value
- },
- || {},
- );
-
- match tail.kind() {
- ty::Bool
- | ty::Char
- | ty::Int(_)
- | ty::Uint(_)
- | ty::Float(_)
- | ty::Str
- | ty::Array(..)
- | ty::Slice(_)
- | ty::RawPtr(..)
- | ty::Ref(..)
- | ty::FnDef(..)
- | ty::FnPtr(..)
- | ty::Dynamic(..)
- | ty::Closure(..)
- | ty::Generator(..)
- | ty::GeneratorWitness(..)
- | ty::Never
- // Extern types have unit metadata, according to RFC 2850
- | ty::Foreign(_)
- // If returned by `struct_tail_without_normalization` this is a unit struct
- // without any fields, or not a struct, and therefore is Sized.
- | ty::Adt(..)
- // If returned by `struct_tail_without_normalization` this is the empty tuple.
- | ty::Tuple(..)
- // Integers and floats are always Sized, and so have unit type metadata.
- | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true,
-
- // type parameters, opaques, and unnormalized projections have pointer
- // metadata if they're known (e.g. by the param_env) to be sized
- ty::Param(_) | ty::Projection(..) | ty::Opaque(..)
- if selcx.infcx().predicate_must_hold_modulo_regions(
- &obligation.with(
- ty::Binder::dummy(ty::TraitRef::new(
- selcx.tcx().require_lang_item(LangItem::Sized, None),
- selcx.tcx().mk_substs_trait(self_ty, &[]),
- ))
- .without_const()
- .to_predicate(selcx.tcx()),
- ),
- ) =>
- {
- true
+ super::ImplSource::Builtin(..) => {
+ // While a builtin impl may be known to exist, the associated type may not yet
+ // be known. Any type with multiple potential associated types is therefore
+ // not eligible.
+ let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
+
+ let lang_items = selcx.tcx().lang_items();
+ if lang_items.discriminant_kind_trait() == Some(poly_trait_ref.def_id()) {
+ match self_ty.kind() {
+ ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Adt(..)
+ | ty::Foreign(_)
+ | ty::Str
+ | ty::Array(..)
+ | ty::Slice(_)
+ | ty::RawPtr(..)
+ | ty::Ref(..)
+ | ty::FnDef(..)
+ | ty::FnPtr(..)
+ | ty::Dynamic(..)
+ | ty::Closure(..)
+ | ty::Generator(..)
+ | ty::GeneratorWitness(..)
+ | ty::Never
+ | ty::Tuple(..)
+ // Integers and floats always have `u8` as their discriminant.
+ | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true,
+
+ // type parameters, opaques, and unnormalized projections have pointer
+ // metadata if they're known (e.g. by the param_env) to be sized
+ ty::Param(_)
+ | ty::Projection(..)
+ | ty::Opaque(..)
+ | ty::Bound(..)
+ | ty::Placeholder(..)
+ | ty::Infer(..)
+ | ty::Error(_) => false,
}
+ } else if lang_items.pointee_trait() == Some(poly_trait_ref.def_id()) {
+ let tail = selcx.tcx().struct_tail_with_normalize(
+ self_ty,
+ |ty| {
+ // We throw away any obligations we get from this, since we normalize
+ // and confirm these obligations once again during confirmation
+ normalize_with_depth(
+ selcx,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ ty,
+ )
+ .value
+ },
+ || {},
+ );
- // FIXME(compiler-errors): are Bound and Placeholder types ever known sized?
- ty::Param(_)
- | ty::Projection(..)
- | ty::Opaque(..)
- | ty::Bound(..)
- | ty::Placeholder(..)
- | ty::Infer(..)
- | ty::Error(_) => {
- if tail.has_infer_types() {
- candidate_set.mark_ambiguous();
+ match tail.kind() {
+ ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Str
+ | ty::Array(..)
+ | ty::Slice(_)
+ | ty::RawPtr(..)
+ | ty::Ref(..)
+ | ty::FnDef(..)
+ | ty::FnPtr(..)
+ | ty::Dynamic(..)
+ | ty::Closure(..)
+ | ty::Generator(..)
+ | ty::GeneratorWitness(..)
+ | ty::Never
+ // Extern types have unit metadata, according to RFC 2850
+ | ty::Foreign(_)
+ // If returned by `struct_tail_without_normalization` this is a unit struct
+ // without any fields, or not a struct, and therefore is Sized.
+ | ty::Adt(..)
+ // If returned by `struct_tail_without_normalization` this is the empty tuple.
+ | ty::Tuple(..)
+ // Integers and floats are always Sized, and so have unit type metadata.
+ | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true,
+
+ // type parameters, opaques, and unnormalized projections have pointer
+ // metadata if they're known (e.g. by the param_env) to be sized
+ ty::Param(_) | ty::Projection(..) | ty::Opaque(..)
+ if selcx.infcx.predicate_must_hold_modulo_regions(
+ &obligation.with(
+ selcx.tcx(),
+ ty::Binder::dummy(
+ selcx.tcx().at(obligation.cause.span()).mk_trait_ref(LangItem::Sized, [self_ty]),
+ )
+ .without_const(),
+ ),
+ ) =>
+ {
+ true
+ }
+
+ // FIXME(compiler-errors): are Bound and Placeholder types ever known sized?
+ ty::Param(_)
+ | ty::Projection(..)
+ | ty::Opaque(..)
+ | ty::Bound(..)
+ | ty::Placeholder(..)
+ | ty::Infer(..)
+ | ty::Error(_) => {
+ if tail.has_infer_types() {
+ candidate_set.mark_ambiguous();
+ }
+ false
}
- false
}
+ } else {
+ bug!("unexpected builtin trait with associated type: {poly_trait_ref:?}")
}
}
super::ImplSource::Param(..) => {
@@ -1757,7 +1738,6 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
false
}
super::ImplSource::AutoImpl(..)
- | super::ImplSource::Builtin(..)
| super::ImplSource::TraitUpcasting(_)
| super::ImplSource::ConstDestruct(_) => {
// These traits have no associated types.
@@ -1820,8 +1800,7 @@ fn confirm_candidate<'cx, 'tcx>(
// when possible for this to work. See `auto-trait-projection-recursion.rs`
// for a case where this matters.
if progress.term.has_infer_regions() {
- progress.term =
- progress.term.fold_with(&mut OpportunisticRegionResolver::new(selcx.infcx()));
+ progress.term = progress.term.fold_with(&mut OpportunisticRegionResolver::new(selcx.infcx));
}
progress
}
@@ -1834,16 +1813,13 @@ fn confirm_select_candidate<'cx, 'tcx>(
match impl_source {
super::ImplSource::UserDefined(data) => confirm_impl_candidate(selcx, obligation, data),
super::ImplSource::Generator(data) => confirm_generator_candidate(selcx, obligation, data),
+ super::ImplSource::Future(data) => confirm_future_candidate(selcx, obligation, data),
super::ImplSource::Closure(data) => confirm_closure_candidate(selcx, obligation, data),
super::ImplSource::FnPointer(data) => confirm_fn_pointer_candidate(selcx, obligation, data),
- super::ImplSource::DiscriminantKind(data) => {
- confirm_discriminant_kind_candidate(selcx, obligation, data)
- }
- super::ImplSource::Pointee(data) => confirm_pointee_candidate(selcx, obligation, data),
+ super::ImplSource::Builtin(data) => confirm_builtin_candidate(selcx, obligation, data),
super::ImplSource::Object(_)
| super::ImplSource::AutoImpl(..)
| super::ImplSource::Param(..)
- | super::ImplSource::Builtin(..)
| super::ImplSource::TraitUpcasting(_)
| super::ImplSource::TraitAlias(..)
| super::ImplSource::ConstDestruct(_) => {
@@ -1907,74 +1883,97 @@ fn confirm_generator_candidate<'cx, 'tcx>(
.with_addl_obligations(obligations)
}
-fn confirm_discriminant_kind_candidate<'cx, 'tcx>(
+fn confirm_future_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
- _: ImplSourceDiscriminantKindData,
+ impl_source: ImplSourceFutureData<'tcx, PredicateObligation<'tcx>>,
) -> Progress<'tcx> {
- let tcx = selcx.tcx();
+ let gen_sig = impl_source.substs.as_generator().poly_sig();
+ let Normalized { value: gen_sig, obligations } = normalize_with_depth(
+ selcx,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ gen_sig,
+ );
- let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
- // We get here from `poly_project_and_unify_type` which replaces bound vars
- // with placeholders
- debug_assert!(!self_ty.has_escaping_bound_vars());
- let substs = tcx.mk_substs([self_ty.into()].iter());
+ debug!(?obligation, ?gen_sig, ?obligations, "confirm_future_candidate");
- let discriminant_def_id = tcx.require_lang_item(LangItem::Discriminant, None);
+ let tcx = selcx.tcx();
+ let fut_def_id = tcx.require_lang_item(LangItem::Future, None);
- let predicate = ty::ProjectionPredicate {
- projection_ty: ty::ProjectionTy { substs, item_def_id: discriminant_def_id },
- term: self_ty.discriminant_ty(tcx).into(),
- };
+ let predicate = super::util::future_trait_ref_and_outputs(
+ tcx,
+ fut_def_id,
+ obligation.predicate.self_ty(),
+ gen_sig,
+ )
+ .map_bound(|(trait_ref, return_ty)| {
+ debug_assert_eq!(tcx.associated_item(obligation.predicate.item_def_id).name, sym::Output);
- // We get here from `poly_project_and_unify_type` which replaces bound vars
- // with placeholders, so dummy is okay here.
- confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
+ ty::ProjectionPredicate {
+ projection_ty: ty::ProjectionTy {
+ substs: trait_ref.substs,
+ item_def_id: obligation.predicate.item_def_id,
+ },
+ term: return_ty.into(),
+ }
+ });
+
+ confirm_param_env_candidate(selcx, obligation, predicate, false)
+ .with_addl_obligations(impl_source.nested)
+ .with_addl_obligations(obligations)
}
-fn confirm_pointee_candidate<'cx, 'tcx>(
+fn confirm_builtin_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
- _: ImplSourcePointeeData,
+ data: ImplSourceBuiltinData<PredicateObligation<'tcx>>,
) -> Progress<'tcx> {
let tcx = selcx.tcx();
- let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
-
- let mut obligations = vec![];
- let (metadata_ty, check_is_sized) = self_ty.ptr_metadata_ty(tcx, |ty| {
- normalize_with_depth_to(
- selcx,
- obligation.param_env,
- obligation.cause.clone(),
- obligation.recursion_depth + 1,
- ty,
- &mut obligations,
- )
- });
- if check_is_sized {
- let sized_predicate = ty::Binder::dummy(ty::TraitRef::new(
- tcx.require_lang_item(LangItem::Sized, None),
- tcx.mk_substs_trait(self_ty, &[]),
- ))
- .without_const()
- .to_predicate(tcx);
- obligations.push(Obligation::new(
- obligation.cause.clone(),
- obligation.param_env,
- sized_predicate,
- ));
- }
-
+ let self_ty = obligation.predicate.self_ty();
let substs = tcx.mk_substs([self_ty.into()].iter());
- let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
-
- let predicate = ty::ProjectionPredicate {
- projection_ty: ty::ProjectionTy { substs, item_def_id: metadata_def_id },
- term: metadata_ty.into(),
+ let lang_items = tcx.lang_items();
+ let item_def_id = obligation.predicate.item_def_id;
+ let trait_def_id = tcx.trait_of_item(item_def_id).unwrap();
+ let (term, obligations) = if lang_items.discriminant_kind_trait() == Some(trait_def_id) {
+ let discriminant_def_id = tcx.require_lang_item(LangItem::Discriminant, None);
+ assert_eq!(discriminant_def_id, item_def_id);
+
+ (self_ty.discriminant_ty(tcx).into(), Vec::new())
+ } else if lang_items.pointee_trait() == Some(trait_def_id) {
+ let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
+ assert_eq!(metadata_def_id, item_def_id);
+
+ let mut obligations = Vec::new();
+ let (metadata_ty, check_is_sized) = self_ty.ptr_metadata_ty(tcx, |ty| {
+ normalize_with_depth_to(
+ selcx,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ ty,
+ &mut obligations,
+ )
+ });
+ if check_is_sized {
+ let sized_predicate = ty::Binder::dummy(
+ tcx.at(obligation.cause.span()).mk_trait_ref(LangItem::Sized, [self_ty]),
+ )
+ .without_const();
+ obligations.push(obligation.with(tcx, sized_predicate));
+ }
+ (metadata_ty.into(), obligations)
+ } else {
+ bug!("unexpected builtin trait with associated type: {:?}", obligation.predicate);
};
+ let predicate =
+ ty::ProjectionPredicate { projection_ty: ty::ProjectionTy { substs, item_def_id }, term };
+
confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
.with_addl_obligations(obligations)
+ .with_addl_obligations(data.nested)
}
fn confirm_fn_pointer_candidate<'cx, 'tcx>(
@@ -1982,7 +1981,7 @@ fn confirm_fn_pointer_candidate<'cx, 'tcx>(
obligation: &ProjectionTyObligation<'tcx>,
fn_pointer_impl_source: ImplSourceFnPointerData<'tcx, PredicateObligation<'tcx>>,
) -> Progress<'tcx> {
- let fn_type = selcx.infcx().shallow_resolve(fn_pointer_impl_source.fn_ty);
+ let fn_type = selcx.infcx.shallow_resolve(fn_pointer_impl_source.fn_ty);
let sig = fn_type.fn_sig(selcx.tcx());
let Normalized { value: sig, obligations } = normalize_with_depth(
selcx,
@@ -2055,7 +2054,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
poly_cache_entry: ty::PolyProjectionPredicate<'tcx>,
potentially_unnormalized_candidate: bool,
) -> Progress<'tcx> {
- let infcx = selcx.infcx();
+ let infcx = selcx.infcx;
let cause = &obligation.cause;
let param_env = obligation.param_env;
@@ -2150,7 +2149,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
// * `substs` ends up as `[u32, S]`
let substs = obligation.predicate.substs.rebase_onto(tcx, trait_def_id, 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.bound_type_of(assoc_ty.item.def_id);
let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst);
let term: ty::EarlyBinder<ty::Term<'tcx>> = if is_const {
@@ -2158,7 +2157,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
crate::traits::InternalSubsts::identity_for_item(tcx, assoc_ty.item.def_id);
let did = ty::WithOptConstParam::unknown(assoc_ty.item.def_id);
let kind = ty::ConstKind::Unevaluated(ty::UnevaluatedConst::new(did, identity_substs));
- ty.map_bound(|ty| tcx.mk_const(ty::ConstS { ty, kind }).into())
+ ty.map_bound(|ty| tcx.mk_const(kind, ty).into())
} else {
ty.map_bound(|ty| ty.into())
};
@@ -2177,7 +2176,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
// Verify that the trait item and its implementation have compatible substs lists
fn check_substs_compatible<'tcx>(
tcx: TyCtxt<'tcx>,
- assoc_ty: &ty::AssocItem,
+ assoc_item: &ty::AssocItem,
substs: ty::SubstsRef<'tcx>,
) -> bool {
fn check_substs_compatible_inner<'tcx>(
@@ -2209,7 +2208,10 @@ fn check_substs_compatible<'tcx>(
true
}
- check_substs_compatible_inner(tcx, tcx.generics_of(assoc_ty.def_id), substs.as_slice())
+ let generics = tcx.generics_of(assoc_item.def_id);
+ // Chop off any additional substs (RPITIT) substs
+ let substs = &substs[0..generics.count().min(substs.len())];
+ check_substs_compatible_inner(tcx, generics, substs)
}
fn confirm_impl_trait_in_trait_candidate<'tcx>(
@@ -2238,11 +2240,27 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
};
}
- let impl_fn_def_id = leaf_def.item.def_id;
// Rebase from {trait}::{fn}::{opaque} to {impl}::{fn}::{opaque},
// since `data.substs` are the impl substs.
let impl_fn_substs =
obligation.predicate.substs.rebase_onto(tcx, tcx.parent(trait_fn_def_id), data.substs);
+ let impl_fn_substs = translate_substs(
+ selcx.infcx,
+ obligation.param_env,
+ data.impl_def_id,
+ impl_fn_substs,
+ leaf_def.defining_node,
+ );
+
+ if !check_substs_compatible(tcx, &leaf_def.item, impl_fn_substs) {
+ let err = tcx.ty_error_with_message(
+ obligation.cause.span,
+ "impl method and trait method have different parameters",
+ );
+ return Progress { term: err.into(), obligations };
+ }
+
+ let impl_fn_def_id = leaf_def.item.def_id;
let cause = ObligationCause::new(
obligation.cause.span,
@@ -2260,6 +2278,7 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
obligations.extend(std::iter::zip(predicates.predicates, predicates.spans).map(
|(pred, span)| {
Obligation::with_depth(
+ tcx,
ObligationCause::new(
obligation.cause.span,
obligation.cause.body_id,
@@ -2276,10 +2295,11 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
},
));
- let ty = super::normalize_to(
+ let ty = normalize_with_depth_to(
selcx,
obligation.param_env,
cause.clone(),
+ obligation.recursion_depth + 1,
tcx.bound_trait_impl_trait_tys(impl_fn_def_id)
.map_bound(|tys| {
tys.map_or_else(|_| tcx.ty_error(), |tys| tys[&obligation.predicate.item_def_id])
@@ -2299,11 +2319,10 @@ fn assoc_ty_own_obligations<'cx, 'tcx>(
nested: &mut Vec<PredicateObligation<'tcx>>,
) {
let tcx = selcx.tcx();
- for predicate in tcx
+ let own = tcx
.predicates_of(obligation.predicate.item_def_id)
- .instantiate_own(tcx, obligation.predicate.substs)
- .predicates
- {
+ .instantiate_own(tcx, obligation.predicate.substs);
+ for (predicate, span) in std::iter::zip(own.predicates, own.spans) {
let normalized = normalize_with_depth_to(
selcx,
obligation.param_env,
@@ -2312,8 +2331,30 @@ fn assoc_ty_own_obligations<'cx, 'tcx>(
predicate,
nested,
);
+
+ let nested_cause = if matches!(
+ obligation.cause.code(),
+ super::CompareImplItemObligation { .. }
+ | super::CheckAssociatedTypeBounds { .. }
+ | super::AscribeUserTypeProvePredicate(..)
+ ) {
+ obligation.cause.clone()
+ } else if span.is_dummy() {
+ ObligationCause::new(
+ obligation.cause.span,
+ obligation.cause.body_id,
+ super::ItemObligation(obligation.predicate.item_def_id),
+ )
+ } else {
+ ObligationCause::new(
+ obligation.cause.span,
+ obligation.cause.body_id,
+ super::BindingObligation(obligation.predicate.item_def_id, span),
+ )
+ };
nested.push(Obligation::with_depth(
- obligation.cause.clone(),
+ tcx,
+ nested_cause,
obligation.recursion_depth + 1,
obligation.param_env,
normalized,
@@ -2385,7 +2426,7 @@ impl<'cx, 'tcx> ProjectionCacheKeyExt<'cx, 'tcx> for ProjectionCacheKey<'tcx> {
selcx: &mut SelectionContext<'cx, 'tcx>,
predicate: ty::PolyProjectionPredicate<'tcx>,
) -> Option<Self> {
- let infcx = selcx.infcx();
+ let infcx = selcx.infcx;
// We don't do cross-snapshot caching of obligations with escaping regions,
// so there's no cache key to use
predicate.no_bound_vars().map(|predicate| {