mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-22 04:34:51 +00:00
IAT: Introduce AliasKind::Inherent
This commit is contained in:
parent
6f8c0557e0
commit
e8139dfd5a
@ -2378,6 +2378,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
//
|
||||
// Select applicable inherent associated type candidates modulo regions.
|
||||
//
|
||||
|
||||
// In contexts that have no inference context, just make a new one.
|
||||
// We do need a local variable to store it, though.
|
||||
let infcx_;
|
||||
@ -2390,7 +2394,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
}
|
||||
};
|
||||
|
||||
let param_env = tcx.param_env(block.owner.to_def_id());
|
||||
// FIXME(inherent_associated_types): Acquiring the ParamEnv this early leads to cycle errors
|
||||
// when inside of an ADT (#108491) or where clause.
|
||||
let param_env = tcx.param_env(block.owner);
|
||||
let cause = ObligationCause::misc(span, block.owner.def_id);
|
||||
|
||||
let mut fulfillment_errors = Vec::new();
|
||||
@ -2398,6 +2404,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
let universe = infcx.create_next_universe();
|
||||
|
||||
// Regions are not considered during selection.
|
||||
// FIXME(non_lifetime_binders): Here we are "truncating" or "flattening" the universes
|
||||
// of type and const binders. Is that correct in the selection phase? See also #109505.
|
||||
let self_ty = tcx.replace_escaping_bound_vars_uncached(
|
||||
self_ty,
|
||||
FnMutDelegate {
|
||||
@ -2413,41 +2421,40 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
|
||||
candidates
|
||||
.iter()
|
||||
.filter_map(|&(impl_, (assoc_item, def_scope))| {
|
||||
.copied()
|
||||
.filter(|&(impl_, _)| {
|
||||
infcx.probe(|_| {
|
||||
let ocx = ObligationCtxt::new_in_snapshot(&infcx);
|
||||
|
||||
let impl_ty = tcx.type_of(impl_);
|
||||
let impl_substs = infcx.fresh_item_substs(impl_);
|
||||
let impl_ty = impl_ty.subst(tcx, impl_substs);
|
||||
let impl_ty = tcx.type_of(impl_).subst(tcx, impl_substs);
|
||||
let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
|
||||
|
||||
// Check that the Self-types can be related.
|
||||
// FIXME(fmease): Should we use `eq` here?
|
||||
ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).ok()?;
|
||||
// Check that the self types can be related.
|
||||
// FIXME(inherent_associated_types): Should we use `eq` here? Method probing uses
|
||||
// `sup` for this situtation, too. What for? To constrain inference variables?
|
||||
if ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).is_err()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check whether the impl imposes obligations we have to worry about.
|
||||
let impl_bounds = tcx.predicates_of(impl_);
|
||||
let impl_bounds = impl_bounds.instantiate(tcx, impl_substs);
|
||||
|
||||
let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_substs);
|
||||
let impl_bounds = ocx.normalize(&cause, param_env, impl_bounds);
|
||||
|
||||
let impl_obligations = traits::predicates_for_generics(
|
||||
|_, _| cause.clone(),
|
||||
param_env,
|
||||
impl_bounds,
|
||||
);
|
||||
|
||||
ocx.register_obligations(impl_obligations);
|
||||
|
||||
let mut errors = ocx.select_where_possible();
|
||||
if !errors.is_empty() {
|
||||
fulfillment_errors.append(&mut errors);
|
||||
return None;
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME(fmease): Unsolved vars can escape this InferCtxt snapshot.
|
||||
Some((assoc_item, def_scope, infcx.resolve_vars_if_possible(impl_substs)))
|
||||
true
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
@ -2456,24 +2463,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
if applicable_candidates.len() > 1 {
|
||||
return Err(self.complain_about_ambiguous_inherent_assoc_type(
|
||||
name,
|
||||
applicable_candidates.into_iter().map(|(candidate, ..)| candidate).collect(),
|
||||
applicable_candidates.into_iter().map(|(_, (candidate, _))| candidate).collect(),
|
||||
span,
|
||||
));
|
||||
}
|
||||
|
||||
if let Some((assoc_item, def_scope, impl_substs)) = applicable_candidates.pop() {
|
||||
if let Some((impl_, (assoc_item, def_scope))) = applicable_candidates.pop() {
|
||||
self.check_assoc_ty(assoc_item, name, def_scope, block, span);
|
||||
|
||||
// FIXME(inherent_associated_types): To fully *confirm* the *probed* candidate, we still
|
||||
// need to relate the Self-type with fresh item substs & register region obligations for
|
||||
// regionck to prove/disprove.
|
||||
// FIXME(fmease): Currently creating throwaway `parent_substs` to please
|
||||
// `create_substs_for_associated_item`. Modify the latter instead (or sth. similar) to
|
||||
// not require the parent substs logic.
|
||||
let parent_substs = InternalSubsts::identity_for_item(tcx, impl_);
|
||||
let substs =
|
||||
self.create_substs_for_associated_item(span, assoc_item, segment, parent_substs);
|
||||
let substs = tcx.mk_substs_from_iter(
|
||||
std::iter::once(ty::GenericArg::from(self_ty))
|
||||
.chain(substs.into_iter().skip(parent_substs.len())),
|
||||
);
|
||||
|
||||
let item_substs =
|
||||
self.create_substs_for_associated_item(span, assoc_item, segment, impl_substs);
|
||||
|
||||
// FIXME(fmease, #106722): Check if the bounds on the parameters of the
|
||||
// associated type hold, if any.
|
||||
let ty = tcx.type_of(assoc_item).subst(tcx, item_substs);
|
||||
let ty = tcx.mk_alias(ty::Inherent, tcx.mk_alias_ty(assoc_item, substs));
|
||||
|
||||
return Ok(Some((ty, assoc_item)));
|
||||
}
|
||||
|
@ -210,6 +210,19 @@ fn do_orphan_check_impl<'tcx>(
|
||||
NonlocalImpl::DisallowOther,
|
||||
),
|
||||
|
||||
// ```
|
||||
// struct S<T>(T);
|
||||
// impl<T: ?Sized> S<T> {
|
||||
// type This = T;
|
||||
// }
|
||||
// impl<T: ?Sized> AutoTrait for S<T>::This {}
|
||||
// ```
|
||||
// FIXME(inherent_associated_types): The example code above currently leads to a cycle
|
||||
ty::Alias(AliasKind::Inherent, _) => (
|
||||
LocalImpl::Disallow { problematic_kind: "associated type" },
|
||||
NonlocalImpl::DisallowOther,
|
||||
),
|
||||
|
||||
// type Opaque = impl Trait;
|
||||
// impl AutoTrait for Opaque {}
|
||||
ty::Alias(AliasKind::Opaque, _) => (
|
||||
|
@ -1938,7 +1938,7 @@ fn is_late_bound_map(
|
||||
ty::Param(param_ty) => {
|
||||
self.arg_is_constrained[param_ty.index as usize] = true;
|
||||
}
|
||||
ty::Alias(ty::Projection, _) => return ControlFlow::Continue(()),
|
||||
ty::Alias(ty::Projection | ty::Inherent, _) => return ControlFlow::Continue(()),
|
||||
_ => (),
|
||||
}
|
||||
t.super_visit_with(self)
|
||||
|
@ -127,7 +127,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
|
||||
// the def_id that this query was called with. We filter to only type and const args here
|
||||
// as a precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't
|
||||
// but it can't hurt to be safe ^^
|
||||
if let ty::Alias(ty::Projection, projection) = ty.kind() {
|
||||
if let ty::Alias(ty::Projection | ty::Inherent, projection) = ty.kind() {
|
||||
let generics = tcx.generics_of(projection.def_id);
|
||||
|
||||
let arg_index = segment
|
||||
|
@ -59,7 +59,7 @@ struct ParameterCollector {
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParameterCollector {
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
match *t.kind() {
|
||||
ty::Alias(ty::Projection, ..) if !self.include_nonconstraining => {
|
||||
ty::Alias(ty::Projection | ty::Inherent, ..) if !self.include_nonconstraining => {
|
||||
// projections are not injective
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
@ -210,6 +210,9 @@ fn insert_required_predicates_to_be_wf<'tcx>(
|
||||
);
|
||||
}
|
||||
|
||||
// FIXME(inherent_associated_types): Handle this case properly.
|
||||
ty::Alias(ty::Inherent, _) => {}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -843,7 +843,7 @@ fn find_param_in_ty<'tcx>(
|
||||
return true;
|
||||
}
|
||||
if let ty::GenericArgKind::Type(ty) = arg.unpack()
|
||||
&& let ty::Alias(ty::Projection, ..) = ty.kind()
|
||||
&& let ty::Alias(ty::Projection | ty::Inherent, ..) = ty.kind()
|
||||
{
|
||||
// This logic may seem a bit strange, but typically when
|
||||
// we have a projection type in a function signature, the
|
||||
|
@ -300,7 +300,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
|
||||
match ty.kind() {
|
||||
ty::Adt(adt_def, _) => Some(*adt_def),
|
||||
// FIXME(#104767): Should we handle bound regions here?
|
||||
ty::Alias(ty::Projection, _) if !ty.has_escaping_bound_vars() => {
|
||||
ty::Alias(ty::Projection | ty::Inherent, _) if !ty.has_escaping_bound_vars() => {
|
||||
self.normalize(span, ty).ty_adt_def()
|
||||
}
|
||||
_ => None,
|
||||
|
@ -2211,7 +2211,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
| ty::Float(_)
|
||||
| ty::Adt(_, _)
|
||||
| ty::Str
|
||||
| ty::Alias(ty::Projection, _)
|
||||
| ty::Alias(ty::Projection | ty::Inherent, _)
|
||||
| ty::Param(_) => format!("{deref_ty}"),
|
||||
// we need to test something like <&[_]>::len or <(&[u32])>::len
|
||||
// and Vec::function();
|
||||
|
@ -125,7 +125,8 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
bug!()
|
||||
}
|
||||
|
||||
(_, ty::Alias(AliasKind::Projection, _)) | (ty::Alias(AliasKind::Projection, _), _)
|
||||
(_, ty::Alias(AliasKind::Projection | AliasKind::Inherent, _))
|
||||
| (ty::Alias(AliasKind::Projection | AliasKind::Inherent, _), _)
|
||||
if self.tcx.trait_solver_next() =>
|
||||
{
|
||||
relation.register_type_relate_obligation(a, b);
|
||||
|
@ -2354,7 +2354,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
let labeled_user_string = match bound_kind {
|
||||
GenericKind::Param(ref p) => format!("the parameter type `{}`", p),
|
||||
GenericKind::Alias(ref p) => match p.kind(self.tcx) {
|
||||
ty::AliasKind::Projection => format!("the associated type `{}`", p),
|
||||
ty::AliasKind::Projection | ty::AliasKind::Inherent => {
|
||||
format!("the associated type `{}`", p)
|
||||
}
|
||||
ty::AliasKind::Opaque => format!("the opaque type `{}`", p),
|
||||
},
|
||||
};
|
||||
|
@ -71,9 +71,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
#traits-as-parameters",
|
||||
);
|
||||
}
|
||||
(ty::Alias(ty::Projection, _), ty::Alias(ty::Projection, _)) => {
|
||||
(ty::Alias(ty::Projection | ty::Inherent, _), ty::Alias(ty::Projection | ty::Inherent, _)) => {
|
||||
diag.note("an associated type was expected, but a different one was found");
|
||||
}
|
||||
// FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
|
||||
(ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p))
|
||||
if !tcx.is_impl_trait_in_trait(proj.def_id) =>
|
||||
{
|
||||
@ -222,7 +223,7 @@ impl<T> Trait<T> for X {
|
||||
diag.span_label(p_span, "this type parameter");
|
||||
}
|
||||
}
|
||||
(ty::Alias(ty::Projection, proj_ty), _) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
|
||||
(ty::Alias(ty::Projection | ty::Inherent, proj_ty), _) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
|
||||
self.expected_projection(
|
||||
diag,
|
||||
proj_ty,
|
||||
@ -231,7 +232,7 @@ impl<T> Trait<T> for X {
|
||||
cause.code(),
|
||||
);
|
||||
}
|
||||
(_, ty::Alias(ty::Projection, proj_ty)) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
|
||||
(_, ty::Alias(ty::Projection | ty::Inherent, proj_ty)) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
|
||||
let msg = format!(
|
||||
"consider constraining the associated type `{}` to `{}`",
|
||||
values.found, values.expected,
|
||||
|
@ -549,6 +549,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
// We can't normalize associated types from `rustc_infer`,
|
||||
// but we can eagerly register inference variables for them.
|
||||
// FIXME(RPITIT): Don't replace RPITITs with inference vars.
|
||||
// FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
|
||||
ty::Alias(ty::Projection, projection_ty)
|
||||
if !projection_ty.has_escaping_bound_vars()
|
||||
&& !tcx.is_impl_trait_in_trait(projection_ty.def_id) =>
|
||||
@ -569,6 +570,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
hidden_ty
|
||||
}
|
||||
// FIXME(RPITIT): This can go away when we move to associated types
|
||||
// FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
|
||||
ty::Alias(
|
||||
ty::Projection,
|
||||
ty::AliasTy { def_id: def_id2, substs: substs2, .. },
|
||||
|
@ -62,6 +62,7 @@ use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::layout::{LayoutError, LayoutOf};
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_middle::ty::TypeVisitableExt;
|
||||
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, VariantDef};
|
||||
use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
|
||||
use rustc_span::edition::Edition;
|
||||
@ -1461,6 +1462,10 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
|
||||
// Bounds are respected for `type X = impl Trait`
|
||||
return;
|
||||
}
|
||||
if cx.tcx.type_of(item.owner_id).skip_binder().has_inherent_projections() {
|
||||
// Bounds are respected for `type X = … Type::Inherent …`
|
||||
return;
|
||||
}
|
||||
// There must not be a where clause
|
||||
if type_alias_generics.predicates.is_empty() {
|
||||
return;
|
||||
@ -1580,7 +1585,6 @@ declare_lint_pass!(
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||
use rustc_middle::ty::visit::TypeVisitableExt;
|
||||
use rustc_middle::ty::Clause;
|
||||
use rustc_middle::ty::PredicateKind::*;
|
||||
|
||||
@ -2917,6 +2921,7 @@ impl ClashingExternDeclarations {
|
||||
| (Generator(..), Generator(..))
|
||||
| (GeneratorWitness(..), GeneratorWitness(..))
|
||||
| (Alias(ty::Projection, ..), Alias(ty::Projection, ..))
|
||||
| (Alias(ty::Inherent, ..), Alias(ty::Inherent, ..))
|
||||
| (Alias(ty::Opaque, ..), Alias(ty::Opaque, ..)) => false,
|
||||
|
||||
// These definitely should have been caught above.
|
||||
|
@ -1119,14 +1119,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||
|
||||
// `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
|
||||
// so they are currently ignored for the purposes of this lint.
|
||||
ty::Param(..) | ty::Alias(ty::Projection, ..)
|
||||
ty::Param(..) | ty::Alias(ty::Projection | ty::Inherent, ..)
|
||||
if matches!(self.mode, CItemKind::Definition) =>
|
||||
{
|
||||
FfiSafe
|
||||
}
|
||||
|
||||
ty::Param(..)
|
||||
| ty::Alias(ty::Projection, ..)
|
||||
| ty::Alias(ty::Projection | ty::Inherent, ..)
|
||||
| ty::Infer(..)
|
||||
| ty::Bound(..)
|
||||
| ty::Error(_)
|
||||
|
@ -1821,6 +1821,16 @@ rustc_queries! {
|
||||
desc { "normalizing `{}`", goal.value.value }
|
||||
}
|
||||
|
||||
/// Do not call this query directly: invoke `normalize` instead.
|
||||
query normalize_inherent_projection_ty(
|
||||
goal: CanonicalProjectionGoal<'tcx>
|
||||
) -> Result<
|
||||
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,
|
||||
NoSolution,
|
||||
> {
|
||||
desc { "normalizing `{}`", goal.value.value }
|
||||
}
|
||||
|
||||
/// Do not call this query directly: invoke `try_normalize_erasing_regions` instead.
|
||||
query try_normalize_generic_arg_after_erasing_regions(
|
||||
goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>
|
||||
|
@ -1846,7 +1846,17 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
let substs = substs.into_iter().map(Into::into);
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
let n = self.generics_of(_def_id).count();
|
||||
let generics = self.generics_of(_def_id);
|
||||
|
||||
let n = if let DefKind::AssocTy = self.def_kind(_def_id)
|
||||
&& let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(_def_id))
|
||||
{
|
||||
// If this is an inherent projection.
|
||||
|
||||
generics.params.len() + 1
|
||||
} else {
|
||||
generics.count()
|
||||
};
|
||||
assert_eq!(
|
||||
(n, Some(n)),
|
||||
substs.size_hint(),
|
||||
@ -2007,7 +2017,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
debug_assert_matches!(
|
||||
(kind, self.def_kind(alias_ty.def_id)),
|
||||
(ty::Opaque, DefKind::OpaqueTy)
|
||||
| (ty::Projection, DefKind::AssocTy)
|
||||
| (ty::Projection | ty::Inherent, DefKind::AssocTy)
|
||||
| (ty::Opaque | ty::Projection, DefKind::ImplTraitPlaceholder)
|
||||
);
|
||||
self.mk_ty_from_kind(Alias(kind, alias_ty))
|
||||
|
@ -265,7 +265,7 @@ impl<'tcx> Ty<'tcx> {
|
||||
ty::Infer(ty::FreshTy(_)) => "fresh type".into(),
|
||||
ty::Infer(ty::FreshIntTy(_)) => "fresh integral type".into(),
|
||||
ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(),
|
||||
ty::Alias(ty::Projection, _) => "associated type".into(),
|
||||
ty::Alias(ty::Projection | ty::Inherent, _) => "associated type".into(),
|
||||
ty::Param(p) => format!("type parameter `{p}`").into(),
|
||||
ty::Alias(ty::Opaque, ..) => if tcx.ty_is_opaque_future(self) { "future".into() } else { "opaque type".into() },
|
||||
ty::Error(_) => "type error".into(),
|
||||
@ -312,7 +312,7 @@ impl<'tcx> Ty<'tcx> {
|
||||
ty::Tuple(..) => "tuple".into(),
|
||||
ty::Placeholder(..) => "higher-ranked type".into(),
|
||||
ty::Bound(..) => "bound type variable".into(),
|
||||
ty::Alias(ty::Projection, _) => "associated type".into(),
|
||||
ty::Alias(ty::Projection | ty::Inherent, _) => "associated type".into(),
|
||||
ty::Param(_) => "type parameter".into(),
|
||||
ty::Alias(ty::Opaque, ..) => "opaque type".into(),
|
||||
}
|
||||
|
@ -176,14 +176,14 @@ impl FlagComputation {
|
||||
self.add_substs(substs);
|
||||
}
|
||||
|
||||
&ty::Alias(ty::Projection, data) => {
|
||||
self.add_flags(TypeFlags::HAS_TY_PROJECTION);
|
||||
self.add_alias_ty(data);
|
||||
}
|
||||
&ty::Alias(kind, data) => {
|
||||
self.add_flags(match kind {
|
||||
ty::Projection => TypeFlags::HAS_TY_PROJECTION,
|
||||
ty::Inherent => TypeFlags::HAS_TY_INHERENT,
|
||||
ty::Opaque => TypeFlags::HAS_TY_OPAQUE,
|
||||
});
|
||||
|
||||
&ty::Alias(ty::Opaque, ty::AliasTy { substs, .. }) => {
|
||||
self.add_flags(TypeFlags::HAS_TY_OPAQUE);
|
||||
self.add_substs(substs);
|
||||
self.add_alias_ty(data);
|
||||
}
|
||||
|
||||
&ty::Dynamic(obj, r, _) => {
|
||||
|
@ -113,6 +113,12 @@ impl<'tcx> Ty<'tcx> {
|
||||
}
|
||||
Never => InhabitedPredicate::False,
|
||||
Param(_) | Alias(ty::Projection, _) => InhabitedPredicate::GenericType(self),
|
||||
// FIXME(inherent_associated_types): Most likely we can just map to `GenericType` like above.
|
||||
// However it's unclear if the substs passed to `InhabitedPredicate::subst` are of the correct
|
||||
// format, i.e. don't contain parent substs. If you hit this case, please verify this beforehand.
|
||||
Alias(ty::Inherent, _) => {
|
||||
bug!("unimplemented: inhabitedness checking for inherent projections")
|
||||
}
|
||||
Tuple(tys) if tys.is_empty() => InhabitedPredicate::True,
|
||||
// use a query for more complex cases
|
||||
Adt(..) | Array(..) | Tuple(_) => tcx.inhabited_predicate_type(self),
|
||||
|
@ -324,7 +324,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
|
||||
let non_zero = !ty.is_unsafe_ptr();
|
||||
let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
|
||||
match tail.kind() {
|
||||
ty::Param(_) | ty::Alias(ty::Projection, _) => {
|
||||
ty::Param(_) | ty::Alias(ty::Projection | ty::Inherent, _) => {
|
||||
debug_assert!(tail.has_non_region_param());
|
||||
Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) })
|
||||
}
|
||||
|
@ -1004,7 +1004,7 @@ impl<'tcx> Term<'tcx> {
|
||||
match self.unpack() {
|
||||
TermKind::Ty(ty) => match ty.kind() {
|
||||
ty::Alias(kind, alias_ty) => match kind {
|
||||
AliasKind::Projection => Some(*alias_ty),
|
||||
AliasKind::Projection | AliasKind::Inherent => Some(*alias_ty),
|
||||
AliasKind::Opaque => None,
|
||||
},
|
||||
_ => None,
|
||||
|
@ -729,7 +729,7 @@ pub trait PrettyPrinter<'tcx>:
|
||||
ty::Foreign(def_id) => {
|
||||
p!(print_def_path(def_id, &[]));
|
||||
}
|
||||
ty::Alias(ty::Projection, ref data) => {
|
||||
ty::Alias(ty::Projection | ty::Inherent, ref data) => {
|
||||
if !(self.should_print_verbose() || NO_QUERIES.with(|q| q.get()))
|
||||
&& self.tcx().is_impl_trait_in_trait(data.def_id)
|
||||
{
|
||||
|
@ -550,6 +550,11 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
|
||||
Ok(tcx.mk_projection(projection_ty.def_id, projection_ty.substs))
|
||||
}
|
||||
|
||||
(&ty::Alias(ty::Inherent, a_data), &ty::Alias(ty::Inherent, b_data)) => {
|
||||
let alias_ty = relation.relate(a_data, b_data)?;
|
||||
Ok(tcx.mk_alias(ty::Inherent, tcx.mk_alias_ty(alias_ty.def_id, alias_ty.substs)))
|
||||
}
|
||||
|
||||
(
|
||||
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, substs: a_substs, .. }),
|
||||
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, substs: b_substs, .. }),
|
||||
|
@ -1190,9 +1190,9 @@ where
|
||||
|
||||
/// Represents the projection of an associated type.
|
||||
///
|
||||
/// For a projection, this would be `<Ty as Trait<...>>::N`.
|
||||
///
|
||||
/// For an opaque type, there is no explicit syntax.
|
||||
/// * For a projection, this would be `<Ty as Trait<...>>::N<...>`.
|
||||
/// * For an inherent projection, this would be `Ty::N<...>`.
|
||||
/// * For an opaque type, there is no explicit syntax.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
pub struct AliasTy<'tcx> {
|
||||
@ -1201,12 +1201,16 @@ pub struct AliasTy<'tcx> {
|
||||
/// For a projection, these are the substitutions for the trait and the
|
||||
/// GAT substitutions, if there are any.
|
||||
///
|
||||
/// For an inherent projection, they consist of the self type and the GAT substitutions,
|
||||
/// if there are any.
|
||||
///
|
||||
/// For RPIT the substitutions are for the generics of the function,
|
||||
/// while for TAIT it is used for the generic parameters of the alias.
|
||||
pub substs: SubstsRef<'tcx>,
|
||||
|
||||
/// The `DefId` of the `TraitItem` for the associated type `N` if this is a projection,
|
||||
/// or the `OpaqueType` item if this is an opaque.
|
||||
/// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether
|
||||
/// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if
|
||||
/// this is an opaque.
|
||||
///
|
||||
/// During codegen, `tcx.type_of(def_id)` can be used to get the type of the
|
||||
/// underlying type if the type is an opaque.
|
||||
@ -1224,6 +1228,7 @@ pub struct AliasTy<'tcx> {
|
||||
impl<'tcx> AliasTy<'tcx> {
|
||||
pub fn kind(self, tcx: TyCtxt<'tcx>) -> ty::AliasKind {
|
||||
match tcx.def_kind(self.def_id) {
|
||||
DefKind::AssocTy if let DefKind::Impl { of_trait: false } = tcx.def_kind(tcx.parent(self.def_id)) => ty::Inherent,
|
||||
DefKind::AssocTy | DefKind::ImplTraitPlaceholder => ty::Projection,
|
||||
DefKind::OpaqueTy => ty::Opaque,
|
||||
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
|
||||
@ -1236,6 +1241,17 @@ impl<'tcx> AliasTy<'tcx> {
|
||||
}
|
||||
|
||||
/// The following methods work only with associated type projections.
|
||||
impl<'tcx> AliasTy<'tcx> {
|
||||
pub fn self_ty(self) -> Ty<'tcx> {
|
||||
self.substs.type_at(0)
|
||||
}
|
||||
|
||||
pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
|
||||
tcx.mk_alias_ty(self.def_id, [self_ty.into()].into_iter().chain(self.substs.iter().skip(1)))
|
||||
}
|
||||
}
|
||||
|
||||
/// The following methods work only with trait associated type projections.
|
||||
impl<'tcx> AliasTy<'tcx> {
|
||||
pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
|
||||
match tcx.def_kind(self.def_id) {
|
||||
@ -1274,13 +1290,28 @@ impl<'tcx> AliasTy<'tcx> {
|
||||
let def_id = self.trait_def_id(tcx);
|
||||
ty::TraitRef::new(tcx, def_id, self.substs.truncate_to(tcx, tcx.generics_of(def_id)))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn self_ty(self) -> Ty<'tcx> {
|
||||
self.substs.type_at(0)
|
||||
}
|
||||
/// The following methods work only with inherent associated type projections.
|
||||
impl<'tcx> AliasTy<'tcx> {
|
||||
/// Transform the substitutions to have the given `impl` substs as the base and the GAT substs on top of that.
|
||||
///
|
||||
/// Does the following transformation:
|
||||
///
|
||||
/// ```text
|
||||
/// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m]
|
||||
///
|
||||
/// I_i impl subst
|
||||
/// P_j GAT subst
|
||||
/// ```
|
||||
pub fn rebase_substs_onto_impl(
|
||||
self,
|
||||
impl_substs: ty::SubstsRef<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> ty::SubstsRef<'tcx> {
|
||||
debug_assert_eq!(self.kind(tcx), ty::Inherent);
|
||||
|
||||
pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
|
||||
tcx.mk_alias_ty(self.def_id, [self_ty.into()].into_iter().chain(self.substs.iter().skip(1)))
|
||||
tcx.mk_substs_from_iter(impl_substs.into_iter().chain(self.substs.into_iter().skip(1)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,9 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> {
|
||||
fn has_projections(&self) -> bool {
|
||||
self.has_type_flags(TypeFlags::HAS_PROJECTION)
|
||||
}
|
||||
fn has_inherent_projections(&self) -> bool {
|
||||
self.has_type_flags(TypeFlags::HAS_TY_INHERENT)
|
||||
}
|
||||
fn has_opaque_types(&self) -> bool {
|
||||
self.has_type_flags(TypeFlags::HAS_TY_OPAQUE)
|
||||
}
|
||||
|
@ -243,6 +243,39 @@ where
|
||||
// This will also visit substs if necessary, so we don't need to recurse.
|
||||
return self.visit_projection_ty(proj);
|
||||
}
|
||||
ty::Alias(ty::Inherent, data) => {
|
||||
if self.def_id_visitor.skip_assoc_tys() {
|
||||
// Visitors searching for minimal visibility/reachability want to
|
||||
// conservatively approximate associated types like `Type::Alias`
|
||||
// as visible/reachable even if `Type` is private.
|
||||
// Ideally, associated types should be substituted in the same way as
|
||||
// free type aliases, but this isn't done yet.
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
self.def_id_visitor.visit_def_id(
|
||||
data.def_id,
|
||||
"associated type",
|
||||
&LazyDefPathStr { def_id: data.def_id, tcx },
|
||||
)?;
|
||||
|
||||
struct LazyDefPathStr<'tcx> {
|
||||
def_id: DefId,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
impl<'tcx> fmt::Display for LazyDefPathStr<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.tcx.def_path_str(self.def_id))
|
||||
}
|
||||
}
|
||||
|
||||
// This will also visit substs if necessary, so we don't need to recurse.
|
||||
return if self.def_id_visitor.shallow() {
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
data.substs.iter().try_for_each(|subst| subst.visit_with(self))
|
||||
};
|
||||
}
|
||||
ty::Dynamic(predicates, ..) => {
|
||||
// All traits in the list are considered the "primary" part of the type
|
||||
// and are visited by shallow visitors.
|
||||
|
@ -20,3 +20,5 @@ trait_selection_negative_positive_conflict = found both positive and negative im
|
||||
.negative_implementation_in_crate = negative implementation in crate `{$negative_impl_cname}`
|
||||
.positive_implementation_here = positive implementation here
|
||||
.positive_implementation_in_crate = positive implementation in crate `{$positive_impl_cname}`
|
||||
|
||||
trait_selection_inherent_projection_normalization_overflow = overflow evaluating associated type `{$ty}`
|
||||
|
@ -89,3 +89,11 @@ impl IntoDiagnostic<'_> for NegativePositiveConflict<'_> {
|
||||
diag
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(trait_selection_inherent_projection_normalization_overflow)]
|
||||
pub struct InherentProjectionNormalizationOverflow {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub ty: String,
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
||||
ty::Dynamic(..)
|
||||
| ty::Param(..)
|
||||
| ty::Foreign(..)
|
||||
| ty::Alias(ty::Projection, ..)
|
||||
| ty::Alias(ty::Projection | ty::Inherent, ..)
|
||||
| ty::Placeholder(..)
|
||||
| ty::Bound(..)
|
||||
| ty::Infer(_) => {
|
||||
|
@ -655,7 +655,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
ty::Dynamic(..)
|
||||
| ty::Param(..)
|
||||
| ty::Foreign(..)
|
||||
| ty::Alias(ty::Projection, ..)
|
||||
| ty::Alias(ty::Projection | ty::Inherent, ..)
|
||||
| ty::Placeholder(..) => Some(Err(NoSolution)),
|
||||
|
||||
ty::Infer(_) | ty::Bound(_, _) => bug!("unexpected type `{self_ty}`"),
|
||||
|
@ -673,7 +673,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OrphanChecker<'tcx> {
|
||||
| ty::RawPtr(..)
|
||||
| ty::Never
|
||||
| ty::Tuple(..)
|
||||
| ty::Alias(ty::Projection, ..) => self.found_non_local_ty(ty),
|
||||
| ty::Alias(ty::Projection | ty::Inherent, ..) => self.found_non_local_ty(ty),
|
||||
|
||||
ty::Param(..) => self.found_param_ty(ty),
|
||||
|
||||
|
@ -1686,13 +1686,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
ty::Tuple(..) => Some(10),
|
||||
ty::Param(..) => Some(11),
|
||||
ty::Alias(ty::Projection, ..) => Some(12),
|
||||
ty::Alias(ty::Opaque, ..) => Some(13),
|
||||
ty::Never => Some(14),
|
||||
ty::Adt(..) => Some(15),
|
||||
ty::Generator(..) => Some(16),
|
||||
ty::Foreign(..) => Some(17),
|
||||
ty::GeneratorWitness(..) => Some(18),
|
||||
ty::GeneratorWitnessMIR(..) => Some(19),
|
||||
ty::Alias(ty::Inherent, ..) => Some(13),
|
||||
ty::Alias(ty::Opaque, ..) => Some(14),
|
||||
ty::Never => Some(15),
|
||||
ty::Adt(..) => Some(16),
|
||||
ty::Generator(..) => Some(17),
|
||||
ty::Foreign(..) => Some(18),
|
||||
ty::GeneratorWitness(..) => Some(19),
|
||||
ty::GeneratorWitnessMIR(..) => Some(20),
|
||||
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,8 @@ pub use self::object_safety::astconv_object_safety_violations;
|
||||
pub use self::object_safety::is_vtable_safe_method;
|
||||
pub use self::object_safety::MethodViolationCode;
|
||||
pub use self::object_safety::ObjectSafetyViolation;
|
||||
pub use self::project::{normalize_projection_type, NormalizeExt};
|
||||
pub use self::project::NormalizeExt;
|
||||
pub use self::project::{normalize_inherent_projection, normalize_projection_type};
|
||||
pub use self::select::{EvaluationCache, SelectionCache, SelectionContext};
|
||||
pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
|
||||
pub use self::specialize::specialization_graph::FutureCompatOverlapError;
|
||||
|
@ -16,6 +16,7 @@ use super::{
|
||||
};
|
||||
use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
|
||||
|
||||
use crate::errors::InherentProjectionNormalizationOverflow;
|
||||
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
|
||||
use crate::traits::error_reporting::TypeErrCtxtExt as _;
|
||||
@ -370,10 +371,14 @@ pub(crate) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
|
||||
reveal: Reveal,
|
||||
) -> bool {
|
||||
match reveal {
|
||||
Reveal::UserFacing => value
|
||||
.has_type_flags(ty::TypeFlags::HAS_TY_PROJECTION | ty::TypeFlags::HAS_CT_PROJECTION),
|
||||
Reveal::UserFacing => value.has_type_flags(
|
||||
ty::TypeFlags::HAS_TY_PROJECTION
|
||||
| ty::TypeFlags::HAS_TY_INHERENT
|
||||
| ty::TypeFlags::HAS_CT_PROJECTION,
|
||||
),
|
||||
Reveal::All => value.has_type_flags(
|
||||
ty::TypeFlags::HAS_TY_PROJECTION
|
||||
| ty::TypeFlags::HAS_TY_INHERENT
|
||||
| ty::TypeFlags::HAS_TY_OPAQUE
|
||||
| ty::TypeFlags::HAS_CT_PROJECTION,
|
||||
),
|
||||
@ -616,6 +621,51 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
|
||||
);
|
||||
normalized_ty
|
||||
}
|
||||
|
||||
ty::Inherent if !data.has_escaping_bound_vars() => {
|
||||
// This branch is *mostly* just an optimization: when we don't
|
||||
// have escaping bound vars, we don't need to replace them with
|
||||
// placeholders (see branch below). *Also*, we know that we can
|
||||
// register an obligation to *later* project, since we know
|
||||
// there won't be bound vars there.
|
||||
|
||||
let data = data.fold_with(self);
|
||||
|
||||
// FIXME(inherent_associated_types): Do we need to honor `self.eager_inference_replacement`
|
||||
// here like `ty::Projection`?
|
||||
normalize_inherent_projection(
|
||||
self.selcx,
|
||||
self.param_env,
|
||||
data,
|
||||
self.cause.clone(),
|
||||
self.depth,
|
||||
&mut self.obligations,
|
||||
)
|
||||
}
|
||||
|
||||
ty::Inherent => {
|
||||
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);
|
||||
let ty = normalize_inherent_projection(
|
||||
self.selcx,
|
||||
self.param_env,
|
||||
data,
|
||||
self.cause.clone(),
|
||||
self.depth,
|
||||
&mut self.obligations,
|
||||
);
|
||||
|
||||
PlaceholderReplacer::replace_placeholders(
|
||||
infcx,
|
||||
mapped_regions,
|
||||
mapped_types,
|
||||
mapped_consts,
|
||||
&self.universes,
|
||||
ty,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1204,6 +1254,95 @@ fn normalize_to_error<'a, 'tcx>(
|
||||
Normalized { value: new_value, obligations: vec![trait_obligation] }
|
||||
}
|
||||
|
||||
/// Confirm and normalize the given inherent projection.
|
||||
#[instrument(level = "debug", skip(selcx, param_env, cause, obligations))]
|
||||
pub fn normalize_inherent_projection<'a, 'b, 'tcx>(
|
||||
selcx: &'a mut SelectionContext<'b, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
alias_ty: ty::AliasTy<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
depth: usize,
|
||||
obligations: &mut Vec<PredicateObligation<'tcx>>,
|
||||
) -> Ty<'tcx> {
|
||||
let tcx = selcx.tcx();
|
||||
|
||||
if !tcx.recursion_limit().value_within_limit(depth) {
|
||||
// Halt compilation because it is important that overflows never be masked.
|
||||
tcx.sess.emit_fatal(InherentProjectionNormalizationOverflow {
|
||||
span: cause.span,
|
||||
ty: alias_ty.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
let impl_def_id = tcx.parent(alias_ty.def_id);
|
||||
let impl_substs = selcx.infcx.fresh_substs_for_item(cause.span, impl_def_id);
|
||||
|
||||
let impl_ty = tcx.type_of(impl_def_id).subst(tcx, impl_substs);
|
||||
let impl_ty =
|
||||
normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, impl_ty, obligations);
|
||||
|
||||
// Infer the generic parameters of the impl by unifying the
|
||||
// impl type with the self type of the projection.
|
||||
let self_ty = alias_ty.self_ty();
|
||||
match selcx.infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, impl_ty, self_ty) {
|
||||
Ok(mut ok) => obligations.append(&mut ok.obligations),
|
||||
Err(_) => {
|
||||
tcx.sess.delay_span_bug(
|
||||
cause.span,
|
||||
format!(
|
||||
"{self_ty:?} was a subtype of {impl_ty:?} during selection but now it is not"
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let substs = alias_ty.rebase_substs_onto_impl(impl_substs, tcx);
|
||||
|
||||
// Register the obligations arising from the impl and from the associated type itself.
|
||||
let predicates = tcx.predicates_of(alias_ty.def_id).instantiate(tcx, substs);
|
||||
for (predicate, span) in predicates {
|
||||
let predicate = normalize_with_depth_to(
|
||||
selcx,
|
||||
param_env,
|
||||
cause.clone(),
|
||||
depth + 1,
|
||||
predicate,
|
||||
obligations,
|
||||
);
|
||||
|
||||
let nested_cause = ObligationCause::new(
|
||||
cause.span,
|
||||
cause.body_id,
|
||||
// FIXME(inherent_associated_types): Since we can't pass along the self type to the
|
||||
// cause code, inherent projections will be printed with identity substitutions in
|
||||
// diagnostics which is not ideal.
|
||||
// Consider creating separate cause codes for this specific situation.
|
||||
if span.is_dummy() {
|
||||
super::ItemObligation(alias_ty.def_id)
|
||||
} else {
|
||||
super::BindingObligation(alias_ty.def_id, span)
|
||||
},
|
||||
);
|
||||
|
||||
obligations.push(Obligation::with_depth(
|
||||
tcx,
|
||||
nested_cause,
|
||||
depth + 1,
|
||||
param_env,
|
||||
predicate,
|
||||
));
|
||||
}
|
||||
|
||||
let ty = tcx.type_of(alias_ty.def_id).subst(tcx, substs);
|
||||
|
||||
let mut ty = selcx.infcx.resolve_vars_if_possible(ty);
|
||||
if ty.has_projections() {
|
||||
ty = normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, ty, obligations);
|
||||
}
|
||||
|
||||
ty
|
||||
}
|
||||
|
||||
enum Projected<'tcx> {
|
||||
Progress(Progress<'tcx>),
|
||||
NoProgress(ty::Term<'tcx>),
|
||||
|
@ -257,11 +257,11 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
|
||||
|
||||
ty::Opaque => ty.try_super_fold_with(self)?,
|
||||
|
||||
ty::Projection => {
|
||||
ty::Projection | ty::Inherent => {
|
||||
// See note in `rustc_trait_selection::traits::project`
|
||||
|
||||
let tcx = self.infcx.tcx;
|
||||
let infcx = self.infcx;
|
||||
let tcx = infcx.tcx;
|
||||
// Just an optimization: When we don't have escaping bound vars,
|
||||
// we don't need to replace them with placeholders.
|
||||
let (data, maps) = if data.has_escaping_bound_vars() {
|
||||
@ -276,12 +276,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
|
||||
let mut orig_values = OriginalQueryValues::default();
|
||||
// HACK(matthewjasper) `'static` is special-cased in selection,
|
||||
// so we cannot canonicalize it.
|
||||
let c_data = self
|
||||
.infcx
|
||||
let c_data = infcx
|
||||
.canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
|
||||
debug!("QueryNormalizer: c_data = {:#?}", c_data);
|
||||
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
|
||||
let result = tcx.normalize_projection_ty(c_data)?;
|
||||
let result = match kind {
|
||||
ty::Projection => tcx.normalize_projection_ty(c_data),
|
||||
ty::Inherent => tcx.normalize_inherent_projection_ty(c_data),
|
||||
_ => unreachable!(),
|
||||
}?;
|
||||
// We don't expect ambiguity.
|
||||
if result.is_ambiguous() {
|
||||
// Rustdoc normalizes possibly not well-formed types, so only
|
||||
@ -294,8 +297,8 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
|
||||
}
|
||||
return Err(NoSolution);
|
||||
}
|
||||
let InferOk { value: result, obligations } =
|
||||
self.infcx.instantiate_query_response_and_region_obligations(
|
||||
let InferOk { value: result, obligations } = infcx
|
||||
.instantiate_query_response_and_region_obligations(
|
||||
self.cause,
|
||||
self.param_env,
|
||||
&orig_values,
|
||||
|
@ -498,7 +498,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
// this trait and type.
|
||||
}
|
||||
ty::Param(..)
|
||||
| ty::Alias(ty::Projection, ..)
|
||||
| ty::Alias(ty::Projection | ty::Inherent, ..)
|
||||
| ty::Placeholder(..)
|
||||
| ty::Bound(..) => {
|
||||
// In these cases, we don't know what the actual
|
||||
|
@ -1268,7 +1268,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
|
||||
// If we have a projection type, make sure to normalize it so we replace it
|
||||
// with a fresh infer variable
|
||||
ty::Alias(ty::Projection, ..) => {
|
||||
ty::Alias(ty::Projection | ty::Inherent, ..) => {
|
||||
let predicate = normalize_with_depth_to(
|
||||
self,
|
||||
obligation.param_env,
|
||||
|
@ -2315,7 +2315,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
||||
| ty::Dynamic(..)
|
||||
| ty::Param(..)
|
||||
| ty::Foreign(..)
|
||||
| ty::Alias(ty::Projection, ..)
|
||||
| ty::Alias(ty::Projection | ty::Inherent, ..)
|
||||
| ty::Bound(..)
|
||||
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
|
||||
bug!("asked to assemble constituent types of unexpected type: {:?}", t);
|
||||
|
@ -605,6 +605,9 @@ impl<'tcx> WfPredicates<'tcx> {
|
||||
walker.skip_current_subtree(); // Subtree handled by compute_projection.
|
||||
self.compute_projection(data);
|
||||
}
|
||||
ty::Alias(ty::Inherent, _) => {
|
||||
// WF if their substs are WF.
|
||||
}
|
||||
|
||||
ty::Adt(def, substs) => {
|
||||
// WfNominalType
|
||||
|
@ -372,6 +372,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
|
||||
substitution: substs.lower_into(interner),
|
||||
}))
|
||||
}
|
||||
ty::Alias(ty::Inherent, _) => unimplemented!(),
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
|
||||
chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy {
|
||||
opaque_ty_id: chalk_ir::OpaqueTyId(def_id),
|
||||
|
@ -10,7 +10,7 @@ use rustc_trait_selection::traits::{self, ObligationCause, SelectionContext};
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
pub(crate) fn provide(p: &mut Providers) {
|
||||
*p = Providers { normalize_projection_ty, ..*p };
|
||||
*p = Providers { normalize_projection_ty, normalize_inherent_projection_ty, ..*p };
|
||||
}
|
||||
|
||||
fn normalize_projection_ty<'tcx>(
|
||||
@ -42,3 +42,30 @@ fn normalize_projection_ty<'tcx>(
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn normalize_inherent_projection_ty<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
goal: CanonicalProjectionGoal<'tcx>,
|
||||
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> {
|
||||
debug!("normalize_provider(goal={:#?})", goal);
|
||||
|
||||
tcx.infer_ctxt().enter_canonical_trait_query(
|
||||
&goal,
|
||||
|ocx, ParamEnvAnd { param_env, value: goal }| {
|
||||
let selcx = &mut SelectionContext::new(ocx.infcx);
|
||||
let cause = ObligationCause::dummy();
|
||||
let mut obligations = vec![];
|
||||
let answer = traits::normalize_inherent_projection(
|
||||
selcx,
|
||||
param_env,
|
||||
goal,
|
||||
cause,
|
||||
0,
|
||||
&mut obligations,
|
||||
);
|
||||
ocx.register_obligations(obligations);
|
||||
|
||||
Ok(NormalizationResult { normalized_ty: answer })
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -229,29 +229,32 @@ bitflags! {
|
||||
|
||||
/// Does this have `Projection`?
|
||||
const HAS_TY_PROJECTION = 1 << 10;
|
||||
/// Does this have `Inherent`?
|
||||
const HAS_TY_INHERENT = 1 << 11;
|
||||
/// Does this have `Opaque`?
|
||||
const HAS_TY_OPAQUE = 1 << 11;
|
||||
const HAS_TY_OPAQUE = 1 << 12;
|
||||
/// Does this have `ConstKind::Unevaluated`?
|
||||
const HAS_CT_PROJECTION = 1 << 12;
|
||||
const HAS_CT_PROJECTION = 1 << 13;
|
||||
|
||||
/// Could this type be normalized further?
|
||||
const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits
|
||||
| TypeFlags::HAS_TY_OPAQUE.bits
|
||||
| TypeFlags::HAS_TY_INHERENT.bits
|
||||
| TypeFlags::HAS_CT_PROJECTION.bits;
|
||||
|
||||
/// Is an error type/const reachable?
|
||||
const HAS_ERROR = 1 << 13;
|
||||
const HAS_ERROR = 1 << 14;
|
||||
|
||||
/// Does this have any region that "appears free" in the type?
|
||||
/// Basically anything but `ReLateBound` and `ReErased`.
|
||||
const HAS_FREE_REGIONS = 1 << 14;
|
||||
const HAS_FREE_REGIONS = 1 << 15;
|
||||
|
||||
/// Does this have any `ReLateBound` regions?
|
||||
const HAS_RE_LATE_BOUND = 1 << 15;
|
||||
const HAS_RE_LATE_BOUND = 1 << 16;
|
||||
/// Does this have any `Bound` types?
|
||||
const HAS_TY_LATE_BOUND = 1 << 16;
|
||||
const HAS_TY_LATE_BOUND = 1 << 17;
|
||||
/// Does this have any `ConstKind::Bound` consts?
|
||||
const HAS_CT_LATE_BOUND = 1 << 17;
|
||||
const HAS_CT_LATE_BOUND = 1 << 18;
|
||||
/// Does this have any bound variables?
|
||||
/// Used to check if a global bound is safe to evaluate.
|
||||
const HAS_LATE_BOUND = TypeFlags::HAS_RE_LATE_BOUND.bits
|
||||
@ -259,20 +262,20 @@ bitflags! {
|
||||
| TypeFlags::HAS_CT_LATE_BOUND.bits;
|
||||
|
||||
/// Does this have any `ReErased` regions?
|
||||
const HAS_RE_ERASED = 1 << 18;
|
||||
const HAS_RE_ERASED = 1 << 19;
|
||||
|
||||
/// Does this value have parameters/placeholders/inference variables which could be
|
||||
/// replaced later, in a way that would change the results of `impl` specialization?
|
||||
const STILL_FURTHER_SPECIALIZABLE = 1 << 19;
|
||||
const STILL_FURTHER_SPECIALIZABLE = 1 << 20;
|
||||
|
||||
/// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`?
|
||||
const HAS_TY_FRESH = 1 << 20;
|
||||
const HAS_TY_FRESH = 1 << 21;
|
||||
|
||||
/// Does this value have `InferConst::Fresh`?
|
||||
const HAS_CT_FRESH = 1 << 21;
|
||||
const HAS_CT_FRESH = 1 << 22;
|
||||
|
||||
/// Does this have `Generator` or `GeneratorWitness`?
|
||||
const HAS_TY_GENERATOR = 1 << 22;
|
||||
const HAS_TY_GENERATOR = 1 << 23;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,6 +37,7 @@ pub enum DynKind {
|
||||
#[derive(Encodable, Decodable, HashStable_Generic)]
|
||||
pub enum AliasKind {
|
||||
Projection,
|
||||
Inherent,
|
||||
Opaque,
|
||||
}
|
||||
|
||||
|
@ -1836,6 +1836,10 @@ pub(crate) fn clean_middle_ty<'tcx>(
|
||||
clean_projection(bound_ty.rebind(*data), cx, parent_def_id)
|
||||
}
|
||||
|
||||
// FIXME(fmease): Clean inherent projections properly. This requires making the trait ref in
|
||||
// `QPathData` optional or alternatively adding a new `clean::Type` variant.
|
||||
ty::Alias(ty::Inherent, _data) => Type::Infer,
|
||||
|
||||
ty::Param(ref p) => {
|
||||
if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) {
|
||||
ImplTrait(bounds)
|
||||
|
@ -1424,6 +1424,7 @@ fn ty_auto_deref_stability<'tcx>(
|
||||
continue;
|
||||
},
|
||||
ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty),
|
||||
ty::Alias(ty::Inherent, _) => unreachable!("inherent projection should have been normalized away above"),
|
||||
ty::Alias(ty::Projection, _) if ty.has_non_region_param() => {
|
||||
TyPosition::new_deref_stable_for_result(precedence, ty)
|
||||
},
|
||||
|
14
tests/rustdoc/inherent-projections.rs
Normal file
14
tests/rustdoc/inherent-projections.rs
Normal file
@ -0,0 +1,14 @@
|
||||
#![feature(inherent_associated_types)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
// FIXME(fmease): Properly render inherent projections.
|
||||
|
||||
// @has inherent_projections/fn.create.html
|
||||
// @has - '//pre[@class="rust item-decl"]' "create() -> _"
|
||||
pub fn create() -> Owner::Metadata {}
|
||||
|
||||
pub struct Owner;
|
||||
|
||||
impl Owner {
|
||||
pub type Metadata = ();
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
// known-bug: #108491
|
||||
|
||||
// FIXME(inherent_associated_types): This should pass.
|
||||
|
||||
struct Foo {
|
||||
bar: Self::Bar,
|
||||
}
|
||||
impl Foo {
|
||||
pub type Bar = usize;
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
error[E0601]: `main` function not found in crate `cycle_iat_inside_of_adt`
|
||||
--> $DIR/cycle-iat-inside-of-adt.rs:10:2
|
||||
|
|
||||
LL | }
|
||||
| ^ consider adding a `main` function to `$DIR/cycle-iat-inside-of-adt.rs`
|
||||
|
||||
error[E0391]: cycle detected when computing predicates of `Foo`
|
||||
--> $DIR/cycle-iat-inside-of-adt.rs:5:1
|
||||
|
|
||||
LL | struct Foo {
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
note: ...which requires computing predicates of `Foo`...
|
||||
--> $DIR/cycle-iat-inside-of-adt.rs:5:1
|
||||
|
|
||||
LL | struct Foo {
|
||||
| ^^^^^^^^^^
|
||||
note: ...which requires computing inferred outlives predicates of `Foo`...
|
||||
--> $DIR/cycle-iat-inside-of-adt.rs:5:1
|
||||
|
|
||||
LL | struct Foo {
|
||||
| ^^^^^^^^^^
|
||||
= note: ...which requires computing the inferred outlives predicates for items in this crate...
|
||||
note: ...which requires computing type of `Foo::bar`...
|
||||
--> $DIR/cycle-iat-inside-of-adt.rs:6:5
|
||||
|
|
||||
LL | bar: Self::Bar,
|
||||
| ^^^^^^^^^^^^^^
|
||||
note: ...which requires computing normalized predicates of `Foo`...
|
||||
--> $DIR/cycle-iat-inside-of-adt.rs:5:1
|
||||
|
|
||||
LL | struct Foo {
|
||||
| ^^^^^^^^^^
|
||||
= note: ...which again requires computing predicates of `Foo`, completing the cycle
|
||||
note: cycle used when collecting item types in top-level module
|
||||
--> $DIR/cycle-iat-inside-of-adt.rs:5:1
|
||||
|
|
||||
LL | / struct Foo {
|
||||
LL | | bar: Self::Bar,
|
||||
LL | | }
|
||||
LL | | impl Foo {
|
||||
LL | | pub type Bar = usize;
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0391, E0601.
|
||||
For more information about an error, try `rustc --explain E0391`.
|
@ -0,0 +1,16 @@
|
||||
// known-bug: unknown
|
||||
|
||||
#![feature(inherent_associated_types)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
// FIXME(inherent_associated_types): This shouldn't lead to a cycle error.
|
||||
|
||||
fn user<T>() where S<T>::P: std::fmt::Debug {}
|
||||
|
||||
struct S<T>;
|
||||
|
||||
impl<T: Copy> S<T> {
|
||||
type P = ();
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,37 @@
|
||||
error[E0391]: cycle detected when computing predicates of `user`
|
||||
--> $DIR/cycle-iat-inside-of-where-predicate.rs:8:1
|
||||
|
|
||||
LL | fn user<T>() where S<T>::P: std::fmt::Debug {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: ...which requires computing predicates of `user`...
|
||||
--> $DIR/cycle-iat-inside-of-where-predicate.rs:8:1
|
||||
|
|
||||
LL | fn user<T>() where S<T>::P: std::fmt::Debug {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: ...which requires computing explicit predicates of `user`...
|
||||
--> $DIR/cycle-iat-inside-of-where-predicate.rs:8:1
|
||||
|
|
||||
LL | fn user<T>() where S<T>::P: std::fmt::Debug {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: ...which requires computing normalized predicates of `user`...
|
||||
--> $DIR/cycle-iat-inside-of-where-predicate.rs:8:1
|
||||
|
|
||||
LL | fn user<T>() where S<T>::P: std::fmt::Debug {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: ...which again requires computing predicates of `user`, completing the cycle
|
||||
note: cycle used when collecting item types in top-level module
|
||||
--> $DIR/cycle-iat-inside-of-where-predicate.rs:3:1
|
||||
|
|
||||
LL | / #![feature(inherent_associated_types)]
|
||||
LL | | #![allow(incomplete_features)]
|
||||
LL | |
|
||||
LL | | // FIXME(inherent_associated_types): This shouldn't lead to a cycle error.
|
||||
... |
|
||||
LL | |
|
||||
LL | | fn main() {}
|
||||
| |____________^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0391`.
|
@ -1,23 +0,0 @@
|
||||
// known-bug: unknown
|
||||
// failure-status: 101
|
||||
// normalize-stderr-test "note: .*\n\n" -> ""
|
||||
// normalize-stderr-test "thread 'rustc' panicked.*\n" -> ""
|
||||
// rustc-env:RUST_BACKTRACE=0
|
||||
|
||||
// FIXME: I presume a type variable that couldn't be solved by `resolve_vars_if_possible`
|
||||
// escapes the InferCtxt snapshot.
|
||||
|
||||
#![feature(inherent_associated_types)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct Cont<T>(T);
|
||||
|
||||
impl<T: Copy> Cont<T> {
|
||||
type Out = Vec<T>;
|
||||
}
|
||||
|
||||
pub fn weird<T: Copy>(x: T) {
|
||||
let _: Cont<_>::Out = vec![true];
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -1,6 +0,0 @@
|
||||
error: the compiler unexpectedly panicked. this is a bug.
|
||||
|
||||
query stack during panic:
|
||||
#0 [typeck] type-checking `weird`
|
||||
#1 [used_trait_imports] finding used_trait_imports `weird`
|
||||
end of query stack
|
@ -1,15 +0,0 @@
|
||||
// known-bug: unknown
|
||||
|
||||
#![feature(inherent_associated_types)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct S<T>(T);
|
||||
|
||||
impl S<()> {
|
||||
type P = i128;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// We fail to infer `_ == ()` here.
|
||||
let _: S<_>::P;
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
// known-bug: unknown
|
||||
// check-pass
|
||||
|
||||
// We currently don't region-check inherent associated type projections at all.
|
||||
|
||||
#![feature(inherent_associated_types)]
|
||||
#![allow(incomplete_features, dead_code)]
|
||||
|
||||
struct S<T>(T);
|
||||
|
||||
impl S<&'static ()> {
|
||||
type T = ();
|
||||
}
|
||||
|
||||
fn usr<'a>() {
|
||||
let _: S::<&'a ()>::T; // this should *fail* but it doesn't!
|
||||
}
|
||||
|
||||
fn main() {}
|
15
tests/ui/associated-inherent-types/bugs/wf-check-skipped.rs
Normal file
15
tests/ui/associated-inherent-types/bugs/wf-check-skipped.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// known-bug: #100041
|
||||
// check-pass
|
||||
|
||||
#![feature(inherent_associated_types)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
// FIXME(inherent_associated_types): This should fail.
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
type Bar<T> = ();
|
||||
}
|
||||
|
||||
fn main() -> Foo::Bar::<Vec<[u32]>> {}
|
@ -31,7 +31,7 @@ fn main() {
|
||||
let _: Select<u8>::Projection = ();
|
||||
|
||||
let _: Choose<NonCopy>::Result = ();
|
||||
let _: Choose<bool>::Result = vec![true];
|
||||
let _: Choose<&str>::Result = vec!["…"]; // regression test for issue #108957
|
||||
}
|
||||
|
||||
// Test if we use the correct `ParamEnv` when proving obligations.
|
||||
|
16
tests/ui/associated-inherent-types/former-subst-ice.rs
Normal file
16
tests/ui/associated-inherent-types/former-subst-ice.rs
Normal file
@ -0,0 +1,16 @@
|
||||
// check-pass
|
||||
|
||||
#![feature(inherent_associated_types)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct Cont<T>(T);
|
||||
|
||||
impl<T: Copy> Cont<T> {
|
||||
type Out = Vec<T>;
|
||||
}
|
||||
|
||||
pub fn weird<T: Copy>(x: T) {
|
||||
let _: Cont<_>::Out = vec![true];
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,15 @@
|
||||
error[E0277]: the trait bound `String: Copy` is not satisfied
|
||||
--> $DIR/generic-associated-types-bad.rs:16:10
|
||||
|
|
||||
LL | const _: Ty::Pr<String> = String::new();
|
||||
| ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
|
||||
|
|
||||
note: required by a bound in `Ty::Pr`
|
||||
--> $DIR/generic-associated-types-bad.rs:10:16
|
||||
|
|
||||
LL | type Pr<T: Copy> = T;
|
||||
| ^^^^ required by this bound in `Ty::Pr`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
@ -0,0 +1,15 @@
|
||||
error[E0277]: the trait bound `Vec<()>: Copy` is not satisfied
|
||||
--> $DIR/generic-associated-types-bad.rs:20:12
|
||||
|
|
||||
LL | let _: Ty::Pr<Vec<()>>;
|
||||
| ^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Vec<()>`
|
||||
|
|
||||
note: required by a bound in `Ty::Pr`
|
||||
--> $DIR/generic-associated-types-bad.rs:10:16
|
||||
|
|
||||
LL | type Pr<T: Copy> = T;
|
||||
| ^^^^ required by this bound in `Ty::Pr`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
@ -0,0 +1,11 @@
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/generic-associated-types-bad.rs:25:12
|
||||
|
|
||||
LL | fn user<'a>() {
|
||||
| -- lifetime `'a` defined here
|
||||
LL | #[cfg(region)]
|
||||
LL | let _: Ty::Static<&'a str> = "";
|
||||
| ^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -0,0 +1,26 @@
|
||||
// revisions: item local region
|
||||
|
||||
#![feature(inherent_associated_types)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Ty {}
|
||||
|
||||
impl Ty {
|
||||
type Pr<T: Copy> = T;
|
||||
|
||||
type Static<Q: 'static> = Q;
|
||||
}
|
||||
|
||||
#[cfg(item)]
|
||||
const _: Ty::Pr<String> = String::new(); //[item]~ the trait bound `String: Copy` is not satisfied
|
||||
|
||||
fn main() {
|
||||
#[cfg(local)]
|
||||
let _: Ty::Pr<Vec<()>>; //[local]~ ERROR the trait bound `Vec<()>: Copy` is not satisfied
|
||||
}
|
||||
|
||||
fn user<'a>() {
|
||||
#[cfg(region)]
|
||||
let _: Ty::Static<&'a str> = ""; //[region]~ ERROR lifetime may not live long enough
|
||||
}
|
11
tests/ui/associated-inherent-types/inference-fail.rs
Normal file
11
tests/ui/associated-inherent-types/inference-fail.rs
Normal file
@ -0,0 +1,11 @@
|
||||
#![feature(inherent_associated_types)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct S<T>(T);
|
||||
|
||||
impl<T> S<T> { type P = (); }
|
||||
|
||||
fn main() {
|
||||
// There is no way to infer this type.
|
||||
let _: S<_>::P = (); //~ ERROR type annotations needed
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/inference-fail.rs:14:14
|
||||
--> $DIR/inference-fail.rs:10:12
|
||||
|
|
||||
LL | let _: S<_>::P;
|
||||
| ^ cannot infer type
|
||||
LL | let _: S<_>::P = ();
|
||||
| ^^^^^^^ cannot infer type for type parameter `T`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
39
tests/ui/associated-inherent-types/inference.rs
Normal file
39
tests/ui/associated-inherent-types/inference.rs
Normal file
@ -0,0 +1,39 @@
|
||||
// Testing inference capabilities.
|
||||
// check-pass
|
||||
|
||||
#![feature(inherent_associated_types)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
use std::convert::identity;
|
||||
|
||||
struct Container<T>(T);
|
||||
|
||||
impl Container<u32> {
|
||||
type Sink = ();
|
||||
}
|
||||
|
||||
impl<Any> Container<Any> {
|
||||
type Thing = Any;
|
||||
}
|
||||
|
||||
impl<T> Container<(T, ())> {
|
||||
type Output = ((), Wrapped<T>);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Inferred via the Self type of the impl.
|
||||
let _: Container<_>::Sink;
|
||||
|
||||
// Inferred via the RHS:
|
||||
|
||||
let _: Container<_>::Thing = 0;
|
||||
|
||||
let _: Container<Wrapped<_>>::Thing = Wrapped(false);
|
||||
|
||||
let _: Container<_>::Output = (drop(1), Wrapped("..."));
|
||||
|
||||
let binding: Container<_>::Thing = Default::default(); // unsolved at this point
|
||||
identity::<String>(binding); // constrained and solved here
|
||||
}
|
||||
|
||||
struct Wrapped<T>(T);
|
25
tests/ui/associated-inherent-types/late-bound-regions.rs
Normal file
25
tests/ui/associated-inherent-types/late-bound-regions.rs
Normal file
@ -0,0 +1,25 @@
|
||||
#![feature(inherent_associated_types)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
// Test if we correctly normalize `S<'a>::P` with respect to late-bound regions.
|
||||
|
||||
type Function = for<'a> fn(&'a i32) -> S<'a>::P;
|
||||
|
||||
struct S<'a>(&'a ());
|
||||
|
||||
trait Inter {
|
||||
type P;
|
||||
}
|
||||
|
||||
impl<'a> S<'a> {
|
||||
type P = &'a i32;
|
||||
}
|
||||
|
||||
fn ret_ref_local<'e>() -> &'e i32 {
|
||||
let f: Function = |x| x;
|
||||
|
||||
let local = 0;
|
||||
f(&local) //~ ERROR cannot return value referencing local variable `local`
|
||||
}
|
||||
|
||||
fn main() {}
|
12
tests/ui/associated-inherent-types/late-bound-regions.stderr
Normal file
12
tests/ui/associated-inherent-types/late-bound-regions.stderr
Normal file
@ -0,0 +1,12 @@
|
||||
error[E0515]: cannot return value referencing local variable `local`
|
||||
--> $DIR/late-bound-regions.rs:22:5
|
||||
|
|
||||
LL | f(&local)
|
||||
| ^^------^
|
||||
| | |
|
||||
| | `local` is borrowed here
|
||||
| returns a value referencing data owned by the current function
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0515`.
|
12
tests/ui/associated-inherent-types/normalization-overflow.rs
Normal file
12
tests/ui/associated-inherent-types/normalization-overflow.rs
Normal file
@ -0,0 +1,12 @@
|
||||
#![feature(inherent_associated_types)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
// FIXME(fmease): I'd prefer to report a cycle error here instead of an overflow one.
|
||||
|
||||
struct T;
|
||||
|
||||
impl T {
|
||||
type This = Self::This; //~ ERROR overflow evaluating associated type `T::This`
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,8 @@
|
||||
error: overflow evaluating associated type `T::This`
|
||||
--> $DIR/normalization-overflow.rs:9:17
|
||||
|
|
||||
LL | type This = Self::This;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
26
tests/ui/associated-inherent-types/private-in-public.rs
Normal file
26
tests/ui/associated-inherent-types/private-in-public.rs
Normal file
@ -0,0 +1,26 @@
|
||||
#![feature(inherent_associated_types)]
|
||||
#![allow(incomplete_features)]
|
||||
#![crate_type = "lib"]
|
||||
|
||||
#![deny(private_in_public)]
|
||||
|
||||
pub type PubAlias0 = PubTy::PrivAssocTy;
|
||||
//~^ ERROR private associated type `PubTy::PrivAssocTy` in public interface (error E0446)
|
||||
//~| WARNING this was previously accepted
|
||||
pub type PubAlias1 = PrivTy::PubAssocTy;
|
||||
//~^ ERROR private type `PrivTy` in public interface (error E0446)
|
||||
//~| WARNING this was previously accepted
|
||||
pub type PubAlias2 = PubTy::PubAssocTy<PrivTy>;
|
||||
//~^ ERROR private type `PrivTy` in public interface (error E0446)
|
||||
//~| WARNING this was previously accepted
|
||||
|
||||
pub struct PubTy;
|
||||
impl PubTy {
|
||||
type PrivAssocTy = ();
|
||||
pub type PubAssocTy<T> = T;
|
||||
}
|
||||
|
||||
struct PrivTy;
|
||||
impl PrivTy {
|
||||
pub type PubAssocTy = ();
|
||||
}
|
34
tests/ui/associated-inherent-types/private-in-public.stderr
Normal file
34
tests/ui/associated-inherent-types/private-in-public.stderr
Normal file
@ -0,0 +1,34 @@
|
||||
error: private associated type `PubTy::PrivAssocTy` in public interface (error E0446)
|
||||
--> $DIR/private-in-public.rs:7:1
|
||||
|
|
||||
LL | pub type PubAlias0 = PubTy::PrivAssocTy;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537>
|
||||
note: the lint level is defined here
|
||||
--> $DIR/private-in-public.rs:5:9
|
||||
|
|
||||
LL | #![deny(private_in_public)]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: private type `PrivTy` in public interface (error E0446)
|
||||
--> $DIR/private-in-public.rs:10:1
|
||||
|
|
||||
LL | pub type PubAlias1 = PrivTy::PubAssocTy;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537>
|
||||
|
||||
error: private type `PrivTy` in public interface (error E0446)
|
||||
--> $DIR/private-in-public.rs:13:1
|
||||
|
|
||||
LL | pub type PubAlias2 = PubTy::PubAssocTy<PrivTy>;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537>
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
14
tests/ui/associated-inherent-types/regionck-0.rs
Normal file
14
tests/ui/associated-inherent-types/regionck-0.rs
Normal file
@ -0,0 +1,14 @@
|
||||
#![feature(inherent_associated_types)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct S<T>(T);
|
||||
|
||||
impl S<&'static ()> {
|
||||
type T = ();
|
||||
}
|
||||
|
||||
fn user<'a>() {
|
||||
let _: S::<&'a ()>::T; //~ ERROR lifetime may not live long enough
|
||||
}
|
||||
|
||||
fn main() {}
|
10
tests/ui/associated-inherent-types/regionck-0.stderr
Normal file
10
tests/ui/associated-inherent-types/regionck-0.stderr
Normal file
@ -0,0 +1,10 @@
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/regionck-0.rs:11:12
|
||||
|
|
||||
LL | fn user<'a>() {
|
||||
| -- lifetime `'a` defined here
|
||||
LL | let _: S::<&'a ()>::T;
|
||||
| ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
13
tests/ui/associated-inherent-types/regionck-1.rs
Normal file
13
tests/ui/associated-inherent-types/regionck-1.rs
Normal file
@ -0,0 +1,13 @@
|
||||
#![feature(inherent_associated_types)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct U;
|
||||
|
||||
impl U {
|
||||
// Don't imply any bounds here.
|
||||
|
||||
type NoTyOutliv<'a, T> = &'a T; //~ ERROR the parameter type `T` may not live long enough
|
||||
type NoReOutliv<'a, 'b> = &'a &'b (); //~ ERROR reference has a longer lifetime than the data it references
|
||||
}
|
||||
|
||||
fn main() {}
|
29
tests/ui/associated-inherent-types/regionck-1.stderr
Normal file
29
tests/ui/associated-inherent-types/regionck-1.stderr
Normal file
@ -0,0 +1,29 @@
|
||||
error[E0309]: the parameter type `T` may not live long enough
|
||||
--> $DIR/regionck-1.rs:9:30
|
||||
|
|
||||
LL | type NoTyOutliv<'a, T> = &'a T;
|
||||
| ^^^^^- help: consider adding a where clause: `where T: 'a`
|
||||
| |
|
||||
| ...so that the reference type `&'a T` does not outlive the data it points at
|
||||
|
||||
error[E0491]: in type `&'a &'b ()`, reference has a longer lifetime than the data it references
|
||||
--> $DIR/regionck-1.rs:10:31
|
||||
|
|
||||
LL | type NoReOutliv<'a, 'b> = &'a &'b ();
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
note: the pointer is valid for the lifetime `'a` as defined here
|
||||
--> $DIR/regionck-1.rs:10:21
|
||||
|
|
||||
LL | type NoReOutliv<'a, 'b> = &'a &'b ();
|
||||
| ^^
|
||||
note: but the referenced data is only valid for the lifetime `'b` as defined here
|
||||
--> $DIR/regionck-1.rs:10:25
|
||||
|
|
||||
LL | type NoReOutliv<'a, 'b> = &'a &'b ();
|
||||
| ^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0309, E0491.
|
||||
For more information about an error, try `rustc --explain E0309`.
|
14
tests/ui/associated-inherent-types/regionck-2.rs
Normal file
14
tests/ui/associated-inherent-types/regionck-2.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// Regression test for issue #109299.
|
||||
|
||||
#![feature(inherent_associated_types)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct Lexer<'d>(&'d ());
|
||||
|
||||
impl Lexer<'static> {
|
||||
type Cursor = ();
|
||||
}
|
||||
|
||||
fn test(_: Lexer::Cursor) {} //~ ERROR mismatched types
|
||||
|
||||
fn main() {}
|
18
tests/ui/associated-inherent-types/regionck-2.stderr
Normal file
18
tests/ui/associated-inherent-types/regionck-2.stderr
Normal file
@ -0,0 +1,18 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/regionck-2.rs:12:12
|
||||
|
|
||||
LL | fn test(_: Lexer::Cursor) {}
|
||||
| ^^^^^^^^^^^^^ lifetime mismatch
|
||||
|
|
||||
= note: expected struct `Lexer<'static>`
|
||||
found struct `Lexer<'_>`
|
||||
note: the anonymous lifetime defined here...
|
||||
--> $DIR/regionck-2.rs:12:12
|
||||
|
|
||||
LL | fn test(_: Lexer::Cursor) {}
|
||||
| ^^^^^
|
||||
= note: ...does not necessarily outlive the static lifetime
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
@ -0,0 +1,26 @@
|
||||
// check-pass
|
||||
// compile-flags: --crate-type=lib
|
||||
|
||||
#![feature(inherent_associated_types)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
// Bounds on the self type play a major role in the resolution of inherent associated types (*).
|
||||
// As a result of that, if a type alias contains any then its bounds have to be respected and the
|
||||
// lint `type_alias_bounds` should not fire.
|
||||
//
|
||||
// FIXME(inherent_associated_types): In the current implementation that is. We might move the
|
||||
// selection phase of IATs from hir_typeck to trait_selection resulting in us not requiring the
|
||||
// ParamEnv that early allowing us to ignore bounds on type aliases again.
|
||||
// Triage this before stabilization.
|
||||
|
||||
#![deny(type_alias_bounds)]
|
||||
|
||||
pub type Alias<T: Bound> = (Source<T>::Assoc,);
|
||||
|
||||
|
||||
pub struct Source<T>(T);
|
||||
pub trait Bound {}
|
||||
|
||||
impl<T: Bound> Source<T> {
|
||||
pub type Assoc = ();
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
#![feature(inherent_associated_types)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct S<T>(T);
|
||||
|
||||
impl<T: Copy> S<T> {
|
||||
type T = T;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _: S<_>::T = String::new(); //~ ERROR the trait bound `String: Copy` is not satisfied
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
error[E0277]: the trait bound `String: Copy` is not satisfied
|
||||
--> $DIR/unsatisfied-bounds-inferred-type.rs:11:12
|
||||
|
|
||||
LL | let _: S<_>::T = String::new();
|
||||
| ^^^^^^^ the trait `Copy` is not implemented for `String`
|
||||
|
|
||||
note: required by a bound in `S<T>::T`
|
||||
--> $DIR/unsatisfied-bounds-inferred-type.rs:6:9
|
||||
|
|
||||
LL | impl<T: Copy> S<T> {
|
||||
| ^^^^ required by this bound in `S<T>::T`
|
||||
LL | type T = T;
|
||||
| - required by a bound in this associated type
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
@ -0,0 +1,14 @@
|
||||
#![feature(inherent_associated_types)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct S<T>(T);
|
||||
|
||||
impl<T> S<T> {
|
||||
type X = ()
|
||||
where
|
||||
T: Copy;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _: S::<String>::X; //~ ERROR the trait bound `String: Copy` is not satisfied
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
error[E0277]: the trait bound `String: Copy` is not satisfied
|
||||
--> $DIR/unsatisfied-bounds-where-clause-on-assoc-ty.rs:13:12
|
||||
|
|
||||
LL | let _: S::<String>::X;
|
||||
| ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
|
||||
|
|
||||
note: required by a bound in `S<T>::X`
|
||||
--> $DIR/unsatisfied-bounds-where-clause-on-assoc-ty.rs:9:12
|
||||
|
|
||||
LL | type X = ()
|
||||
| - required by a bound in this associated type
|
||||
LL | where
|
||||
LL | T: Copy;
|
||||
| ^^^^ required by this bound in `S<T>::X`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Reference in New Issue
Block a user