Auto merge of #135186 - camelid:const-path-multi, r=BoxyUwU

mgca: Lower all const paths as `ConstArgKind::Path`

When `#![feature(min_generic_const_args)]` is enabled, we now lower all
const paths in generic arg position to `hir::ConstArgKind::Path`. We
then lower assoc const paths to `ty::ConstKind::Unevaluated` since we
can no longer use the anon const expression lowering machinery. In the
process of implementing this, I factored out `hir_ty_lowering` code that
is now shared between lowering assoc types and assoc consts.

This PR also introduces a `#[type_const]` attribute for trait assoc
consts that are allowed as const args. However, we still need to
implement code to check that assoc const definitions satisfy
`#[type_const]` if present (basically is it a const path or a
monomorphic anon const).

r? `@BoxyUwU`
This commit is contained in:
bors 2025-03-04 22:37:37 +00:00
commit 08db600e8e
35 changed files with 602 additions and 148 deletions

View File

@ -124,10 +124,19 @@ impl Path {
self.segments.first().is_some_and(|segment| segment.ident.name == kw::PathRoot)
}
/// If this path is a single identifier with no arguments, does not ensure
/// that the path resolves to a const param, the caller should check this.
pub fn is_potential_trivial_const_arg(&self) -> bool {
matches!(self.segments[..], [PathSegment { args: None, .. }])
/// Check if this path is potentially a trivial const arg, i.e., one that can _potentially_
/// be represented without an anon const in the HIR.
///
/// If `allow_mgca_arg` is true (as should be the case in most situations when
/// `#![feature(min_generic_const_args)]` is enabled), then this always returns true
/// because all paths are valid.
///
/// Otherwise, it returns true iff the path has exactly one segment, and it has no generic args
/// (i.e., it is _potentially_ a const parameter).
#[tracing::instrument(level = "debug", ret)]
pub fn is_potential_trivial_const_arg(&self, allow_mgca_arg: bool) -> bool {
allow_mgca_arg
|| self.segments.len() == 1 && self.segments.iter().all(|seg| seg.args.is_none())
}
}
@ -1208,22 +1217,31 @@ pub struct Expr {
}
impl Expr {
/// Could this expr be either `N`, or `{ N }`, where `N` is a const parameter.
/// Check if this expression is potentially a trivial const arg, i.e., one that can _potentially_
/// be represented without an anon const in the HIR.
///
/// If this is not the case, name resolution does not resolve `N` when using
/// `min_const_generics` as more complex expressions are not supported.
/// This will unwrap at most one block level (curly braces). After that, if the expression
/// is a path, it mostly dispatches to [`Path::is_potential_trivial_const_arg`].
/// See there for more info about `allow_mgca_arg`.
///
/// Does not ensure that the path resolves to a const param, the caller should check this.
/// The only additional thing to note is that when `allow_mgca_arg` is false, this function
/// will only allow paths with no qself, before dispatching to the `Path` function of
/// the same name.
///
/// Does not ensure that the path resolves to a const param/item, the caller should check this.
/// This also does not consider macros, so it's only correct after macro-expansion.
pub fn is_potential_trivial_const_arg(&self) -> bool {
pub fn is_potential_trivial_const_arg(&self, allow_mgca_arg: bool) -> bool {
let this = self.maybe_unwrap_block();
if let ExprKind::Path(None, path) = &this.kind
&& path.is_potential_trivial_const_arg()
{
true
if allow_mgca_arg {
matches!(this.kind, ExprKind::Path(..))
} else {
false
if let ExprKind::Path(None, path) = &this.kind
&& path.is_potential_trivial_const_arg(allow_mgca_arg)
{
true
} else {
false
}
}
}

View File

@ -1094,7 +1094,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
.and_then(|partial_res| partial_res.full_res())
{
if !res.matches_ns(Namespace::TypeNS)
&& path.is_potential_trivial_const_arg()
&& path.is_potential_trivial_const_arg(false)
{
debug!(
"lower_generic_arg: Lowering type argument as const argument: {:?}",
@ -2061,8 +2061,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
) -> &'hir hir::ConstArg<'hir> {
let tcx = self.tcx;
// FIXME(min_generic_const_args): we only allow one-segment const paths for now
let ct_kind = if path.is_potential_trivial_const_arg()
let ct_kind = if path
.is_potential_trivial_const_arg(tcx.features().min_generic_const_args())
&& (tcx.features().min_generic_const_args()
|| matches!(res, Res::Def(DefKind::ConstParam, _)))
{
@ -2072,7 +2072,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
path,
ParamMode::Optional,
AllowReturnTypeNotation::No,
// FIXME(min_generic_const_args): update for `fn foo() -> Bar<FOO<impl Trait>>` support
// FIXME(mgca): update for `fn foo() -> Bar<FOO<impl Trait>>` support
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);
@ -2136,19 +2136,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
};
let maybe_res =
self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res());
// FIXME(min_generic_const_args): we only allow one-segment const paths for now
if let ExprKind::Path(None, path) = &expr.kind
&& path.is_potential_trivial_const_arg()
if let ExprKind::Path(qself, path) = &expr.kind
&& path.is_potential_trivial_const_arg(tcx.features().min_generic_const_args())
&& (tcx.features().min_generic_const_args()
|| matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _))))
{
let qpath = self.lower_qpath(
expr.id,
&None,
qself,
path,
ParamMode::Optional,
AllowReturnTypeNotation::No,
// FIXME(min_generic_const_args): update for `fn foo() -> Bar<FOO<impl Trait>>` support
// FIXME(mgca): update for `fn foo() -> Bar<FOO<impl Trait>>` support
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);

View File

@ -190,7 +190,8 @@ fn make_format_args(
&& let [stmt] = block.stmts.as_slice()
&& let StmtKind::Expr(expr) = &stmt.kind
&& let ExprKind::Path(None, path) = &expr.kind
&& path.is_potential_trivial_const_arg()
&& path.segments.len() == 1
&& path.segments[0].args.is_none()
{
err.multipart_suggestion(
"quote your inlined format argument to use as string literal",

View File

@ -576,6 +576,13 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
EncodeCrossCrate::Yes, experimental!(patchable_function_entry)
),
// Probably temporary component of min_generic_const_args.
// `#[type_const] const ASSOC: usize;`
gated!(
type_const, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::Yes, min_generic_const_args, experimental!(type_const),
),
// ==========================================================================
// Internal attributes: Stability, deprecation, and unsafe:
// ==========================================================================

View File

@ -45,6 +45,7 @@ use tracing::{debug, instrument};
use crate::check::intrinsic::intrinsic_operation_unsafety;
use crate::errors;
use crate::hir_ty_lowering::errors::assoc_kind_str;
use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason};
pub(crate) mod dump;
@ -443,13 +444,14 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
self.tcx.at(span).type_param_predicates((self.item_def_id, def_id, assoc_name))
}
fn lower_assoc_ty(
fn lower_assoc_shared(
&self,
span: Span,
item_def_id: DefId,
item_segment: &hir::PathSegment<'tcx>,
item_segment: &rustc_hir::PathSegment<'tcx>,
poly_trait_ref: ty::PolyTraitRef<'tcx>,
) -> Ty<'tcx> {
kind: ty::AssocKind,
) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
let item_args = self.lowerer().lower_generic_args_of_assoc_item(
span,
@ -457,7 +459,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
item_segment,
trait_ref.args,
);
Ty::new_projection_from_args(self.tcx(), item_def_id, item_args)
Ok((item_def_id, item_args))
} else {
// There are no late-bound regions; we can just ignore the binder.
let (mut mpart_sugg, mut inferred_sugg) = (None, None);
@ -518,16 +520,14 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
}
_ => {}
}
Ty::new_error(
self.tcx(),
self.tcx().dcx().emit_err(errors::AssociatedItemTraitUninferredGenericParams {
span,
inferred_sugg,
bound,
mpart_sugg,
what: "type",
}),
)
Err(self.tcx().dcx().emit_err(errors::AssociatedItemTraitUninferredGenericParams {
span,
inferred_sugg,
bound,
mpart_sugg,
what: assoc_kind_str(kind),
}))
}
}

View File

@ -468,11 +468,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// Good error for `where Trait::method(..): Send`.
let Some(self_ty) = opt_self_ty else {
return self.error_missing_qpath_self_ty(
let guar = self.error_missing_qpath_self_ty(
trait_def_id,
hir_ty.span,
item_segment,
ty::AssocKind::Type,
);
return Ty::new_error(tcx, guar);
};
let self_ty = self.lower_ty(self_ty);

View File

@ -385,14 +385,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
})
}
pub(super) fn report_ambiguous_assoc_ty(
pub(super) fn report_ambiguous_assoc(
&self,
span: Span,
types: &[String],
traits: &[String],
name: Symbol,
kind: ty::AssocKind,
) -> ErrorGuaranteed {
let mut err = struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type");
let kind_str = assoc_kind_str(kind);
let mut err =
struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated {kind_str}");
if self
.tcx()
.resolutions(())
@ -417,7 +420,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
span,
format!(
"if there were a type named `Type` that implements a trait named \
`Trait` with associated type `{name}`, you could use the \
`Trait` with associated {kind_str} `{name}`, you could use the \
fully-qualified path",
),
format!("<Type as Trait>::{name}"),
@ -440,7 +443,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
span,
format!(
"if there were a type named `Example` that implemented one of the \
traits with associated type `{name}`, you could use the \
traits with associated {kind_str} `{name}`, you could use the \
fully-qualified path",
),
traits.iter().map(|trait_str| format!("<Example as {trait_str}>::{name}")),
@ -451,7 +454,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
err.span_suggestion_verbose(
span,
format!(
"if there were a trait named `Example` with associated type `{name}` \
"if there were a trait named `Example` with associated {kind_str} `{name}` \
implemented for `{type_str}`, you could use the fully-qualified path",
),
format!("<{type_str} as Example>::{name}"),
@ -462,7 +465,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
err.span_suggestions(
span,
format!(
"if there were a trait named `Example` with associated type `{name}` \
"if there were a trait named `Example` with associated {kind_str} `{name}` \
implemented for one of the types, you could use the fully-qualified \
path",
),
@ -491,7 +494,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
err.emit()
}
pub(crate) fn complain_about_ambiguous_inherent_assoc_ty(
pub(crate) fn complain_about_ambiguous_inherent_assoc(
&self,
name: Ident,
candidates: Vec<DefId>,
@ -552,13 +555,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
// FIXME(inherent_associated_types): Find similarly named associated types and suggest them.
pub(crate) fn complain_about_inherent_assoc_ty_not_found(
pub(crate) fn complain_about_inherent_assoc_not_found(
&self,
name: Ident,
self_ty: Ty<'tcx>,
candidates: Vec<(DefId, (DefId, DefId))>,
fulfillment_errors: Vec<FulfillmentError<'tcx>>,
span: Span,
kind: ty::AssocKind,
) -> ErrorGuaranteed {
// FIXME(fmease): This was copied in parts from an old version of `rustc_hir_typeck::method::suggest`.
// Either
@ -568,12 +572,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let tcx = self.tcx();
let kind_str = assoc_kind_str(kind);
let adt_did = self_ty.ty_adt_def().map(|def| def.did());
let add_def_label = |err: &mut Diag<'_>| {
if let Some(did) = adt_did {
err.span_label(
tcx.def_span(did),
format!("associated item `{name}` not found for this {}", tcx.def_descr(did)),
format!(
"associated {kind_str} `{name}` not found for this {}",
tcx.def_descr(did)
),
);
}
};
@ -600,11 +608,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self.dcx(),
name.span,
E0220,
"associated type `{name}` not found for `{self_ty}` in the current scope"
"associated {kind_str} `{name}` not found for `{self_ty}` in the current scope"
);
err.span_label(name.span, format!("associated item not found in `{self_ty}`"));
err.note(format!(
"the associated type was found for\n{type_candidates}{additional_types}",
"the associated {kind_str} was found for\n{type_candidates}{additional_types}",
));
add_def_label(&mut err);
return err.emit();
@ -685,7 +693,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let mut err = self.dcx().struct_span_err(
name.span,
format!("the associated type `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied")
format!("the associated {kind_str} `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied")
);
if !bounds.is_empty() {
err.note(format!(
@ -695,7 +703,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
err.span_label(
name.span,
format!("associated type cannot be referenced on `{self_ty}` due to unsatisfied trait bounds")
format!("associated {kind_str} cannot be referenced on `{self_ty}` due to unsatisfied trait bounds")
);
for (span, mut bounds) in bound_spans {
@ -1614,7 +1622,7 @@ fn generics_args_err_extend<'a>(
}
}
pub(super) fn assoc_kind_str(kind: ty::AssocKind) -> &'static str {
pub(crate) fn assoc_kind_str(kind: ty::AssocKind) -> &'static str {
match kind {
ty::AssocKind::Fn => "function",
ty::AssocKind::Const => "constant",

View File

@ -115,7 +115,7 @@ fn generic_arg_mismatch_err(
body.value.kind
&& let Res::Def(DefKind::Fn { .. }, id) = path.res
{
// FIXME(min_generic_const_args): this branch is dead once new const path lowering
// FIXME(mgca): this branch is dead once new const path lowering
// (for single-segment paths) is no longer gated
err.help(format!("`{}` is a function item, not a type", tcx.item_name(id)));
err.help("function item types cannot be named directly");

View File

@ -44,14 +44,16 @@ use rustc_middle::ty::{
};
use rustc_middle::{bug, span_bug};
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
use rustc_session::parse::feature_err;
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw};
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::wf::object_region_bounds;
use rustc_trait_selection::traits::{self, ObligationCtxt};
use rustc_type_ir::Upcast;
use tracing::{debug, instrument};
use self::errors::assoc_kind_str;
use crate::check::check_abi_fn_ptr;
use crate::errors::{
AmbiguousLifetimeBound, BadReturnTypeNotation, InvalidBaseType, NoVariantNamed,
@ -152,7 +154,7 @@ pub trait HirTyLowerer<'tcx> {
assoc_name: Ident,
) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]>;
/// Lower an associated type to a projection.
/// Lower an associated type/const (from a trait) to a projection.
///
/// This method has to be defined by the concrete lowering context because
/// dealing with higher-ranked trait references depends on its capabilities:
@ -164,13 +166,14 @@ pub trait HirTyLowerer<'tcx> {
///
/// The canonical example of this is associated type `T::P` where `T` is a type
/// param constrained by `T: for<'a> Trait<'a>` and where `Trait` defines `P`.
fn lower_assoc_ty(
fn lower_assoc_shared(
&self,
span: Span,
item_def_id: DefId,
item_segment: &hir::PathSegment<'tcx>,
poly_trait_ref: ty::PolyTraitRef<'tcx>,
) -> Ty<'tcx>;
kind: ty::AssocKind,
) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed>;
fn lower_fn_sig(
&self,
@ -245,6 +248,42 @@ pub enum FeedConstTy<'a, 'tcx> {
No,
}
#[derive(Debug, Clone, Copy)]
enum LowerAssocMode {
Type { permit_variants: bool },
Const,
}
impl LowerAssocMode {
fn kind(self) -> ty::AssocKind {
match self {
LowerAssocMode::Type { .. } => ty::AssocKind::Type,
LowerAssocMode::Const => ty::AssocKind::Const,
}
}
fn def_kind(self) -> DefKind {
match self {
LowerAssocMode::Type { .. } => DefKind::AssocTy,
LowerAssocMode::Const => DefKind::AssocConst,
}
}
fn permit_variants(self) -> bool {
match self {
LowerAssocMode::Type { permit_variants } => permit_variants,
// FIXME(mgca): Support paths like `Option::<T>::None` or `Option::<T>::Some` which resolve to const ctors/fn items respectively
LowerAssocMode::Const => false,
}
}
}
#[derive(Debug, Clone, Copy)]
enum LoweredAssoc<'tcx> {
Term(DefId, GenericArgsRef<'tcx>),
Variant { adt: Ty<'tcx>, variant_did: DefId },
}
/// New-typed boolean indicating whether explicit late-bound lifetimes
/// are present in a set of generic arguments.
///
@ -630,7 +669,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
(args, arg_count)
}
#[instrument(level = "debug", skip_all)]
#[instrument(level = "debug", skip(self))]
pub fn lower_generic_args_of_assoc_item(
&self,
span: Span,
@ -638,7 +677,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
item_segment: &hir::PathSegment<'tcx>,
parent_args: GenericArgsRef<'tcx>,
) -> GenericArgsRef<'tcx> {
debug!(?span, ?item_def_id, ?item_segment);
let (args, _) =
self.lower_generic_args_of_path(span, item_def_id, parent_args, item_segment, None);
if let Some(c) = item_segment.args().constraints.first() {
@ -1118,7 +1156,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// NOTE: When this function starts resolving `Trait::AssocTy` successfully
// it should also start reporting the `BARE_TRAIT_OBJECTS` lint.
#[instrument(level = "debug", skip_all, ret)]
pub fn lower_assoc_path(
pub fn lower_assoc_path_ty(
&self,
hir_ref_id: HirId,
span: Span,
@ -1127,6 +1165,72 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
assoc_segment: &'tcx hir::PathSegment<'tcx>,
permit_variants: bool,
) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
let tcx = self.tcx();
match self.lower_assoc_path_shared(
hir_ref_id,
span,
qself_ty,
qself,
assoc_segment,
LowerAssocMode::Type { permit_variants },
)? {
LoweredAssoc::Term(def_id, args) => {
let alias_ty = ty::AliasTy::new_from_args(tcx, def_id, args);
let ty = Ty::new_alias(tcx, alias_ty.kind(tcx), alias_ty);
Ok((ty, tcx.def_kind(def_id), def_id))
}
LoweredAssoc::Variant { adt, variant_did } => Ok((adt, DefKind::Variant, variant_did)),
}
}
#[instrument(level = "debug", skip_all, ret)]
fn lower_assoc_path_const(
&self,
hir_ref_id: HirId,
span: Span,
qself_ty: Ty<'tcx>,
qself: &'tcx hir::Ty<'tcx>,
assoc_segment: &'tcx hir::PathSegment<'tcx>,
) -> Result<Const<'tcx>, ErrorGuaranteed> {
let tcx = self.tcx();
let (def_id, args) = match self.lower_assoc_path_shared(
hir_ref_id,
span,
qself_ty,
qself,
assoc_segment,
LowerAssocMode::Const,
)? {
LoweredAssoc::Term(def_id, args) => {
if !tcx.associated_item(def_id).is_type_const_capable(tcx) {
let mut err = tcx.dcx().struct_span_err(
span,
"use of trait associated const without `#[type_const]`",
);
err.note("the declaration in the trait must be marked with `#[type_const]`");
return Err(err.emit());
}
(def_id, args)
}
// FIXME(mgca): implement support for this once ready to support all adt ctor expressions,
// not just const ctors
LoweredAssoc::Variant { .. } => {
span_bug!(span, "unexpected variant res for type associated const path")
}
};
Ok(Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(def_id, args)))
}
#[instrument(level = "debug", skip_all, ret)]
fn lower_assoc_path_shared(
&self,
hir_ref_id: HirId,
span: Span,
qself_ty: Ty<'tcx>,
qself: &'tcx hir::Ty<'tcx>,
assoc_segment: &'tcx hir::PathSegment<'tcx>,
mode: LowerAssocMode,
) -> Result<LoweredAssoc<'tcx>, ErrorGuaranteed> {
debug!(%qself_ty, ?assoc_segment.ident);
let tcx = self.tcx();
@ -1141,13 +1245,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.iter()
.find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident(tcx), adt_def.did()));
if let Some(variant_def) = variant_def {
if permit_variants {
if mode.permit_variants() {
tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
let _ = self.prohibit_generic_args(
slice::from_ref(assoc_segment).iter(),
GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def },
);
return Ok((qself_ty, DefKind::Variant, variant_def.def_id));
return Ok(LoweredAssoc::Variant {
adt: qself_ty,
variant_did: variant_def.def_id,
});
} else {
variant_resolution = Some(variant_def.def_id);
}
@ -1155,15 +1262,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
// FIXME(inherent_associated_types, #106719): Support self types other than ADTs.
if let Some((ty, did)) = self.probe_inherent_assoc_ty(
assoc_ident,
if let Some((did, args)) = self.probe_inherent_assoc_shared(
assoc_segment,
adt_def.did(),
qself_ty,
hir_ref_id,
span,
mode.kind(),
)? {
return Ok((ty, DefKind::AssocTy, did));
return Ok(LoweredAssoc::Term(did, args));
}
}
@ -1192,7 +1299,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
)
},
AssocItemQSelf::SelfTyAlias,
ty::AssocKind::Type,
mode.kind(),
assoc_ident,
span,
None,
@ -1204,14 +1311,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
) => self.probe_single_ty_param_bound_for_assoc_item(
param_did.expect_local(),
qself.span,
ty::AssocKind::Type,
mode.kind(),
assoc_ident,
span,
)?,
_ => {
let kind_str = assoc_kind_str(mode.kind());
let reported = if variant_resolution.is_some() {
// Variant in type position
let msg = format!("expected type, found variant `{assoc_ident}`");
let msg = format!("expected {kind_str}, found variant `{assoc_ident}`");
self.dcx().span_err(span, msg)
} else if qself_ty.is_enum() {
let mut err = self.dcx().create_err(NoVariantNamed {
@ -1310,11 +1418,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self.probe_traits_that_match_assoc_ty(qself_ty, assoc_ident);
// Don't print `ty::Error` to the user.
self.report_ambiguous_assoc_ty(
self.report_ambiguous_assoc(
span,
&[qself_ty.to_string()],
&traits,
assoc_ident.name,
mode.kind(),
)
};
return Err(reported);
@ -1322,10 +1431,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
};
let trait_did = bound.def_id();
let assoc_ty = self
.probe_assoc_item(assoc_ident, ty::AssocKind::Type, hir_ref_id, span, trait_did)
.expect("failed to find associated type");
let ty = self.lower_assoc_ty(span, assoc_ty.def_id, assoc_segment, bound);
let assoc_item = self
.probe_assoc_item(assoc_ident, mode.kind(), hir_ref_id, span, trait_did)
.expect("failed to find associated item");
let (def_id, args) =
self.lower_assoc_shared(span, assoc_item.def_id, assoc_segment, bound, mode.kind())?;
let result = LoweredAssoc::Term(def_id, args);
if let Some(variant_def_id) = variant_resolution {
tcx.node_span_lint(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| {
@ -1341,7 +1452,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
};
could_refer_to(DefKind::Variant, variant_def_id, "");
could_refer_to(DefKind::AssocTy, assoc_ty.def_id, " also");
could_refer_to(mode.def_kind(), assoc_item.def_id, " also");
lint.span_suggestion(
span,
@ -1351,36 +1462,51 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
);
});
}
Ok((ty, DefKind::AssocTy, assoc_ty.def_id))
Ok(result)
}
fn probe_inherent_assoc_ty(
fn probe_inherent_assoc_shared(
&self,
name: Ident,
segment: &hir::PathSegment<'tcx>,
adt_did: DefId,
self_ty: Ty<'tcx>,
block: HirId,
span: Span,
) -> Result<Option<(Ty<'tcx>, DefId)>, ErrorGuaranteed> {
kind: ty::AssocKind,
) -> Result<Option<(DefId, GenericArgsRef<'tcx>)>, ErrorGuaranteed> {
let tcx = self.tcx();
// Don't attempt to look up inherent associated types when the feature is not enabled.
// Theoretically it'd be fine to do so since we feature-gate their definition site.
// However, due to current limitations of the implementation (caused by us performing
// selection during HIR ty lowering instead of in the trait solver), IATs can lead to cycle
// errors (#108491) which mask the feature-gate error, needlessly confusing users
// who use IATs by accident (#113265).
if !tcx.features().inherent_associated_types() {
return Ok(None);
match kind {
// Don't attempt to look up inherent associated types when the feature is not enabled.
// Theoretically it'd be fine to do so since we feature-gate their definition site.
// However, due to current limitations of the implementation (caused by us performing
// selection during HIR ty lowering instead of in the trait solver), IATs can lead to cycle
// errors (#108491) which mask the feature-gate error, needlessly confusing users
// who use IATs by accident (#113265).
ty::AssocKind::Type => return Ok(None),
ty::AssocKind::Const => {
// We also gate the mgca codepath for type-level uses of inherent consts
// with the inherent_associated_types feature gate since it relies on the
// same machinery and has similar rough edges.
return Err(feature_err(
&tcx.sess,
sym::inherent_associated_types,
span,
"inherent associated types are unstable",
)
.emit());
}
ty::AssocKind::Fn => unreachable!(),
}
}
let name = segment.ident;
let candidates: Vec<_> = tcx
.inherent_impls(adt_did)
.iter()
.filter_map(|&impl_| {
let (item, scope) =
self.probe_assoc_item_unchecked(name, ty::AssocKind::Type, block, impl_)?;
let (item, scope) = self.probe_assoc_item_unchecked(name, kind, block, impl_)?;
Some((impl_, (item.def_id, scope)))
})
.collect();
@ -1395,13 +1521,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// In contexts that have no inference context, just make a new one.
// We do need a local variable to store it, though.
let infcx_;
let infcx = match self.infcx() {
Some(infcx) => infcx,
None => {
assert!(!self_ty.has_infer());
infcx_ = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis());
&infcx_
&tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis())
}
};
@ -1420,8 +1544,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&mut universes,
self_ty,
|self_ty| {
self.select_inherent_assoc_type_candidates(
infcx, name, span, self_ty, param_env, candidates,
self.select_inherent_assoc_candidates(
infcx, name, span, self_ty, param_env, candidates, kind,
)
},
)?;
@ -1438,13 +1562,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.chain(args.into_iter().skip(parent_args.len())),
);
let ty =
Ty::new_alias(tcx, ty::Inherent, ty::AliasTy::new_from_args(tcx, assoc_item, args));
Ok(Some((ty, assoc_item)))
Ok(Some((assoc_item, args)))
}
fn select_inherent_assoc_type_candidates(
fn select_inherent_assoc_candidates(
&self,
infcx: &InferCtxt<'tcx>,
name: Ident,
@ -1452,6 +1573,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self_ty: Ty<'tcx>,
param_env: ParamEnv<'tcx>,
candidates: Vec<(DefId, (DefId, DefId))>,
kind: ty::AssocKind,
) -> Result<(DefId, (DefId, DefId)), ErrorGuaranteed> {
let tcx = self.tcx();
let mut fulfillment_errors = Vec::new();
@ -1496,17 +1618,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.collect();
match &applicable_candidates[..] {
&[] => Err(self.complain_about_inherent_assoc_ty_not_found(
&[] => Err(self.complain_about_inherent_assoc_not_found(
name,
self_ty,
candidates,
fulfillment_errors,
span,
kind,
)),
&[applicable_candidate] => Ok(applicable_candidate),
&[_, ..] => Err(self.complain_about_ambiguous_inherent_assoc_ty(
&[_, ..] => Err(self.complain_about_ambiguous_inherent_assoc(
name,
applicable_candidates.into_iter().map(|(_, (candidate, _))| candidate).collect(),
span,
@ -1638,7 +1761,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
/// Lower a qualified path to a type.
#[instrument(level = "debug", skip_all)]
fn lower_qpath(
fn lower_qpath_ty(
&self,
span: Span,
opt_self_ty: Option<Ty<'tcx>>,
@ -1646,13 +1769,64 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
trait_segment: &hir::PathSegment<'tcx>,
item_segment: &hir::PathSegment<'tcx>,
) -> Ty<'tcx> {
match self.lower_qpath_shared(
span,
opt_self_ty,
item_def_id,
trait_segment,
item_segment,
ty::AssocKind::Type,
) {
Ok((item_def_id, item_args)) => {
Ty::new_projection_from_args(self.tcx(), item_def_id, item_args)
}
Err(guar) => Ty::new_error(self.tcx(), guar),
}
}
/// Lower a qualified path to a const.
#[instrument(level = "debug", skip_all)]
fn lower_qpath_const(
&self,
span: Span,
opt_self_ty: Option<Ty<'tcx>>,
item_def_id: DefId,
trait_segment: &hir::PathSegment<'tcx>,
item_segment: &hir::PathSegment<'tcx>,
) -> Const<'tcx> {
match self.lower_qpath_shared(
span,
opt_self_ty,
item_def_id,
trait_segment,
item_segment,
ty::AssocKind::Const,
) {
Ok((item_def_id, item_args)) => {
let uv = ty::UnevaluatedConst::new(item_def_id, item_args);
Const::new_unevaluated(self.tcx(), uv)
}
Err(guar) => Const::new_error(self.tcx(), guar),
}
}
#[instrument(level = "debug", skip_all)]
fn lower_qpath_shared(
&self,
span: Span,
opt_self_ty: Option<Ty<'tcx>>,
item_def_id: DefId,
trait_segment: &hir::PathSegment<'tcx>,
item_segment: &hir::PathSegment<'tcx>,
kind: ty::AssocKind,
) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed> {
let tcx = self.tcx();
let trait_def_id = tcx.parent(item_def_id);
debug!(?trait_def_id);
let Some(self_ty) = opt_self_ty else {
return self.error_missing_qpath_self_ty(trait_def_id, span, item_segment);
return Err(self.error_missing_qpath_self_ty(trait_def_id, span, item_segment, kind));
};
debug!(?self_ty);
@ -1663,7 +1837,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let item_args =
self.lower_generic_args_of_assoc_item(span, item_def_id, item_segment, trait_ref.args);
Ty::new_projection_from_args(tcx, item_def_id, item_args)
Ok((item_def_id, item_args))
}
fn error_missing_qpath_self_ty(
@ -1671,7 +1845,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
trait_def_id: DefId,
span: Span,
item_segment: &hir::PathSegment<'tcx>,
) -> Ty<'tcx> {
kind: ty::AssocKind,
) -> ErrorGuaranteed {
let tcx = self.tcx();
let path_str = tcx.def_path_str(trait_def_id);
@ -1707,9 +1882,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
// references the trait. Relevant for the first case in
// `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs`
let reported =
self.report_ambiguous_assoc_ty(span, &type_names, &[path_str], item_segment.ident.name);
Ty::new_error(tcx, reported)
self.report_ambiguous_assoc(span, &type_names, &[path_str], item_segment.ident.name, kind)
}
pub fn prohibit_generic_args<'a>(
@ -2013,7 +2186,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
path.segments[..path.segments.len() - 2].iter(),
GenericsArgsErrExtend::None,
);
self.lower_qpath(
self.lower_qpath_ty(
span,
opt_self_ty,
def_id,
@ -2167,11 +2340,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
self.lower_const_path_resolved(opt_self_ty, path, hir_id)
}
hir::ConstArgKind::Path(qpath) => ty::Const::new_error_with_message(
tcx,
qpath.span(),
format!("Const::lower_const_arg: invalid qpath {qpath:?}"),
),
hir::ConstArgKind::Path(hir::QPath::TypeRelative(qself, segment)) => {
debug!(?qself, ?segment);
let ty = self.lower_ty(qself);
self.lower_assoc_path_const(hir_id, const_arg.span(), ty, qself, segment)
.unwrap_or_else(|guar| Const::new_error(tcx, guar))
}
hir::ConstArgKind::Path(qpath @ hir::QPath::LangItem(..)) => {
ty::Const::new_error_with_message(
tcx,
qpath.span(),
format!("Const::lower_const_arg: invalid qpath {qpath:?}"),
)
}
hir::ConstArgKind::Anon(anon) => self.lower_anon_const(anon),
hir::ConstArgKind::Infer(span, ()) => self.ct_infer(None, span),
}
@ -2207,6 +2388,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
);
ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(did, args))
}
Res::Def(DefKind::AssocConst, did) => {
debug_assert!(path.segments.len() >= 2);
let _ = self.prohibit_generic_args(
path.segments[..path.segments.len() - 2].iter(),
GenericsArgsErrExtend::None,
);
self.lower_qpath_const(
span,
opt_self_ty,
did,
&path.segments[path.segments.len() - 2],
path.segments.last().unwrap(),
)
}
Res::Def(DefKind::Static { .. }, _) => {
span_bug!(span, "use of bare `static` ConstArgKind::Path's not yet supported")
}
@ -2223,7 +2418,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// Exhaustive match to be clear about what exactly we're considering to be
// an invalid Res for a const path.
Res::Def(
res @ (Res::Def(
DefKind::Mod
| DefKind::Enum
| DefKind::Variant
@ -2237,7 +2432,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
| DefKind::Union
| DefKind::Trait
| DefKind::ForeignTy
| DefKind::AssocConst
| DefKind::TyParam
| DefKind::Macro(_)
| DefKind::LifetimeParam
@ -2260,12 +2454,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
| Res::Local(_)
| Res::ToolMod
| Res::NonMacroAttr(_)
| Res::Err => Const::new_error_with_message(tcx, span, "invalid Res for const path"),
| Res::Err) => Const::new_error_with_message(
tcx,
span,
format!("invalid Res {res:?} for const path"),
),
}
}
/// Literals and const generic parameters are eagerly converted to a constant, everything else
/// becomes `Unevaluated`.
/// Literals are eagerly converted to a constant, everything else becomes `Unevaluated`.
#[instrument(skip(self), level = "debug")]
fn lower_anon_const(&self, anon: &AnonConst) -> Const<'tcx> {
let tcx = self.tcx();
@ -2464,7 +2661,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
hir::TyKind::Path(hir::QPath::TypeRelative(qself, segment)) => {
debug!(?qself, ?segment);
let ty = self.lower_ty(qself);
self.lower_assoc_path(hir_ty.hir_id, hir_ty.span, ty, qself, segment, false)
self.lower_assoc_path_ty(hir_ty.hir_id, hir_ty.span, ty, qself, segment, false)
.map(|(ty, _, _)| ty)
.unwrap_or_else(|guar| Ty::new_error(tcx, guar))
}

View File

@ -2174,7 +2174,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let result = self
.lowerer()
.lower_assoc_path(hir_id, path_span, ty.raw, qself, segment, true);
.lower_assoc_path_ty(hir_id, path_span, ty.raw, qself, segment, true);
let ty = result
.map(|(ty, _, _)| ty)
.unwrap_or_else(|guar| Ty::new_error(self.tcx(), guar));

View File

@ -17,7 +17,7 @@ use rustc_infer::infer;
use rustc_infer::traits::Obligation;
use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt};
use rustc_session::Session;
use rustc_span::{self, DUMMY_SP, Ident, Span, sym};
use rustc_span::{self, DUMMY_SP, ErrorGuaranteed, Ident, Span, sym};
use rustc_trait_selection::error_reporting::TypeErrCtxt;
use rustc_trait_selection::error_reporting::infer::sub_relations::SubRelations;
use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt};
@ -308,15 +308,17 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
))
}
fn lower_assoc_ty(
fn lower_assoc_shared(
&self,
span: Span,
item_def_id: DefId,
item_segment: &hir::PathSegment<'tcx>,
item_segment: &rustc_hir::PathSegment<'tcx>,
poly_trait_ref: ty::PolyTraitRef<'tcx>,
) -> Ty<'tcx> {
_kind: ty::AssocKind,
) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
let trait_ref = self.instantiate_binder_with_fresh_vars(
span,
// FIXME(mgca): this should be assoc const if that is the `kind`
infer::BoundRegionConversionTime::AssocTypeProjection(item_def_id),
poly_trait_ref,
);
@ -328,7 +330,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
trait_ref.args,
);
Ty::new_projection_from_args(self.tcx(), item_def_id, item_args)
Ok((item_def_id, item_args))
}
fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>> {

View File

@ -3,7 +3,7 @@ use rustc_hir as hir;
use rustc_hir::def::{DefKind, Namespace};
use rustc_hir::def_id::DefId;
use rustc_macros::{Decodable, Encodable, HashStable};
use rustc_span::{Ident, Symbol};
use rustc_span::{Ident, Symbol, sym};
use super::{TyCtxt, Visibility};
use crate::ty;
@ -108,6 +108,24 @@ impl AssocItem {
pub fn is_impl_trait_in_trait(&self) -> bool {
self.opt_rpitit_info.is_some()
}
/// Returns true if:
/// - This trait associated item has the `#[type_const]` attribute,
/// - If it is in a trait impl, the item from the original trait has this attribute, or
/// - It is an inherent assoc const.
pub fn is_type_const_capable(&self, tcx: TyCtxt<'_>) -> bool {
if self.kind != ty::AssocKind::Const {
return false;
}
let def_id = match (self.container, self.trait_item_def_id) {
(AssocItemContainer::Trait, _) => self.def_id,
(AssocItemContainer::Impl, Some(trait_item_did)) => trait_item_did,
// Inherent impl but this attr is only applied to trait assoc items.
(AssocItemContainer::Impl, None) => return true,
};
tcx.has_attr(def_id, sym::type_const)
}
}
#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]

View File

@ -14,6 +14,7 @@ use rustc_attr_parsing::{AttributeKind, ReprAttr, find_attr};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey};
use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalModDefId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{
@ -257,6 +258,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
[sym::coroutine, ..] => {
self.check_coroutine(attr, target);
}
[sym::type_const, ..] => {
self.check_type_const(hir_id,attr, target);
}
[sym::linkage, ..] => self.check_linkage(attr, span, target),
[sym::rustc_pub_transparent, ..] => self.check_rustc_pub_transparent(attr.span(), span, attrs),
[
@ -2519,6 +2523,23 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
}
fn check_type_const(&self, hir_id: HirId, attr: &Attribute, target: Target) {
let tcx = self.tcx;
if target == Target::AssocConst
&& let parent = tcx.parent(hir_id.expect_owner().to_def_id())
&& self.tcx.def_kind(parent) == DefKind::Trait
{
return;
} else {
self.dcx()
.struct_span_err(
attr.span(),
"`#[type_const]` must only be applied to trait associated constants",
)
.emit();
}
}
fn check_linkage(&self, attr: &Attribute, span: Span, target: Target) {
match target {
Target::Fn

View File

@ -1202,7 +1202,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
if let TyKind::Path(None, ref path) = ty.kind
// We cannot disambiguate multi-segment paths right now as that requires type
// checking.
&& path.is_potential_trivial_const_arg()
&& path.is_potential_trivial_const_arg(false)
{
let mut check_ns = |ns| {
self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns)
@ -4630,11 +4630,12 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
constant, anon_const_kind
);
self.resolve_anon_const_manual(
constant.value.is_potential_trivial_const_arg(),
anon_const_kind,
|this| this.resolve_expr(&constant.value, None),
)
let is_trivial_const_arg = constant
.value
.is_potential_trivial_const_arg(self.r.tcx.features().min_generic_const_args());
self.resolve_anon_const_manual(is_trivial_const_arg, anon_const_kind, |this| {
this.resolve_expr(&constant.value, None)
})
}
/// There are a few places that we need to resolve an anon const but we did not parse an
@ -4794,8 +4795,11 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
// Constant arguments need to be treated as AnonConst since
// that is how they will be later lowered to HIR.
if const_args.contains(&idx) {
let is_trivial_const_arg = argument.is_potential_trivial_const_arg(
self.r.tcx.features().min_generic_const_args(),
);
self.resolve_anon_const_manual(
argument.is_potential_trivial_const_arg(),
is_trivial_const_arg,
AnonConstKind::ConstArg(IsRepeatExpr::No),
|this| this.resolve_expr(argument, None),
);

View File

@ -2084,6 +2084,7 @@ symbols! {
type_ascribe,
type_ascription,
type_changing_struct_update,
type_const,
type_id,
type_ir_inherent,
type_length_limit,

View File

@ -3250,7 +3250,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
obligation: &PredicateObligation<'tcx>,
span: Span,
) -> Result<Diag<'a>, ErrorGuaranteed> {
if !self.tcx.features().generic_const_exprs() {
if !self.tcx.features().generic_const_exprs()
&& !self.tcx.features().min_generic_const_args()
{
let guar = self
.dcx()
.struct_span_err(span, "constant expression depends on a generic parameter")

View File

@ -85,6 +85,12 @@ pub fn is_const_evaluatable<'tcx>(
}
_ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"),
}
} else if tcx.features().min_generic_const_args() {
// This is a sanity check to make sure that non-generics consts are checked to
// be evaluatable in case they aren't cchecked elsewhere. This will NOT error
// if the const uses generics, as desired.
crate::traits::evaluate_const(infcx, unexpanded_ct, param_env);
Ok(())
} else {
let uv = match unexpanded_ct.kind() {
ty::ConstKind::Unevaluated(uv) => uv,

View File

@ -410,7 +410,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let predicate = obligation.predicate.skip_binder();
let mut assume = predicate.trait_ref.args.const_at(2);
// FIXME(min_generic_const_exprs): We should shallowly normalize this.
// FIXME(mgca): We should shallowly normalize this.
if self.tcx().features().generic_const_exprs() {
assume = crate::traits::evaluate_const(self.infcx, assume, obligation.param_env)
}

View File

@ -2,7 +2,7 @@ error[E0220]: associated type `Cursor` not found for `Lexer<T>` in the current s
--> $DIR/issue-109299-1.rs:10:40
|
LL | struct Lexer<T>(T);
| --------------- associated item `Cursor` not found for this struct
| --------------- associated type `Cursor` not found for this struct
...
LL | type X = impl for<T> Fn() -> Lexer<T>::Cursor;
| ^^^^^^ associated item not found in `Lexer<T>`
@ -14,7 +14,7 @@ error[E0220]: associated type `Cursor` not found for `Lexer<T>` in the current s
--> $DIR/issue-109299-1.rs:10:40
|
LL | struct Lexer<T>(T);
| --------------- associated item `Cursor` not found for this struct
| --------------- associated type `Cursor` not found for this struct
...
LL | type X = impl for<T> Fn() -> Lexer<T>::Cursor;
| ^^^^^^ associated item not found in `Lexer<T>`

View File

@ -2,7 +2,7 @@ error[E0220]: associated type `Pr` not found for `S<bool>` in the current scope
--> $DIR/not-found-self-type-differs-shadowing-trait-item.rs:28:23
|
LL | struct S<T>(T);
| ----------- associated item `Pr` not found for this struct
| ----------- associated type `Pr` not found for this struct
...
LL | let _: S::<bool>::Pr = ();
| ^^ associated item not found in `S<bool>`

View File

@ -2,7 +2,7 @@ error[E0220]: associated type `Proj` not found for `Family<Option<()>>` in the c
--> $DIR/not-found-self-type-differs.rs:15:32
|
LL | struct Family<T>(T);
| ---------------- associated item `Proj` not found for this struct
| ---------------- associated type `Proj` not found for this struct
...
LL | let _: Family<Option<()>>::Proj;
| ^^^^ associated item not found in `Family<Option<()>>`
@ -15,7 +15,7 @@ error[E0220]: associated type `Proj` not found for `Family<PathBuf>` in the curr
--> $DIR/not-found-self-type-differs.rs:16:40
|
LL | struct Family<T>(T);
| ---------------- associated item `Proj` not found for this struct
| ---------------- associated type `Proj` not found for this struct
...
LL | let _: Family<std::path::PathBuf>::Proj = ();
| ^^^^ associated item not found in `Family<PathBuf>`

View File

@ -2,7 +2,7 @@ error: the associated type `Yield` exists for `Container<[u8]>`, but its trait b
--> $DIR/not-found-unsatisfied-bounds-0.rs:19:29
|
LL | struct Container<T: ?Sized>(T);
| --------------------------- associated item `Yield` not found for this struct
| --------------------------- associated type `Yield` not found for this struct
...
LL | let _: Container<[u8]>::Yield = 1;
| ^^^^^ associated type cannot be referenced on `Container<[u8]>` due to unsatisfied trait bounds
@ -14,7 +14,7 @@ error: the associated type `Combination` exists for `Duple<String, Rc<str>>`, bu
--> $DIR/not-found-unsatisfied-bounds-0.rs:20:45
|
LL | struct Duple<T, U>(T, U);
| ------------------ associated item `Combination` not found for this struct
| ------------------ associated type `Combination` not found for this struct
...
LL | let _: Duple<String, std::rc::Rc<str>>::Combination;
| ^^^^^^^^^^^ associated type cannot be referenced on `Duple<String, Rc<str>>` due to unsatisfied trait bounds

View File

@ -5,7 +5,7 @@ LL | let _: Container<T>::Proj = String::new();
| ^^^^ associated type cannot be referenced on `Container<T>` due to unsatisfied trait bounds
...
LL | struct Container<T>(T);
| ------------------- associated item `Proj` not found for this struct
| ------------------- associated type `Proj` not found for this struct
|
= note: the following trait bounds were not satisfied:
`T: Clone`

View File

@ -2,7 +2,7 @@ error: the associated type `X` exists for `S<Featureless, Featureless>`, but its
--> $DIR/not-found-unsatisfied-bounds-in-multiple-impls.rs:19:43
|
LL | struct S<A, B>(A, B);
| -------------- associated item `X` not found for this struct
| -------------- associated type `X` not found for this struct
LL | struct Featureless;
| ------------------ doesn't satisfy `Featureless: One` or `Featureless: Two`
...

View File

@ -0,0 +1,15 @@
#![feature(min_generic_const_args)]
#![expect(incomplete_features)]
trait Tr {
const N: usize;
}
struct Blah<const N: usize>;
fn foo() -> Blah<{ Tr::N }> {
//~^ ERROR ambiguous associated constant
todo!()
}
fn main() {}

View File

@ -0,0 +1,15 @@
error[E0223]: ambiguous associated constant
--> $DIR/ambiguous-assoc-const.rs:10:20
|
LL | fn foo() -> Blah<{ Tr::N }> {
| ^^^^^
|
help: if there were a type named `Example` that implemented `Tr`, you could use the fully-qualified path
|
LL - fn foo() -> Blah<{ Tr::N }> {
LL + fn foo() -> Blah<{ <Example as Tr>::N }> {
|
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0223`.

View File

@ -0,0 +1,14 @@
#![feature(min_generic_const_args)]
#![allow(incomplete_features)]
pub trait Tr {
const SIZE: usize;
}
fn mk_array<T: Tr>(_x: T) -> [(); T::SIZE] {
//~^ ERROR type_const
[(); T::SIZE]
//~^ ERROR type_const
}
fn main() {}

View File

@ -0,0 +1,18 @@
error: use of trait associated const without `#[type_const]`
--> $DIR/assoc-const-without-type_const.rs:8:35
|
LL | fn mk_array<T: Tr>(_x: T) -> [(); T::SIZE] {
| ^^^^^^^
|
= note: the declaration in the trait must be marked with `#[type_const]`
error: use of trait associated const without `#[type_const]`
--> $DIR/assoc-const-without-type_const.rs:10:10
|
LL | [(); T::SIZE]
| ^^^^^^^
|
= note: the declaration in the trait must be marked with `#[type_const]`
error: aborting due to 2 previous errors

View File

@ -0,0 +1,15 @@
//@ check-pass
#![feature(min_generic_const_args)]
#![allow(incomplete_features)]
pub trait Tr<X> {
#[type_const]
const SIZE: usize;
}
fn mk_array<T: Tr<bool>>(_x: T) -> [(); <T as Tr<bool>>::SIZE] {
[(); T::SIZE]
}
fn main() {}

View File

@ -0,0 +1,17 @@
trait Tr {
#[type_const()]
//~^ ERROR malformed
//~| ERROR experimental
const N: usize;
}
struct S;
impl Tr for S {
#[type_const]
//~^ ERROR must only be applied to trait associated constants
//~| ERROR experimental
const N: usize = 0;
}
fn main() {}

View File

@ -0,0 +1,35 @@
error: malformed `type_const` attribute input
--> $DIR/bad-type_const-syntax.rs:2:5
|
LL | #[type_const()]
| ^^^^^^^^^^^^^^^ help: must be of the form: `#[type_const]`
error[E0658]: the `#[type_const]` attribute is an experimental feature
--> $DIR/bad-type_const-syntax.rs:2:5
|
LL | #[type_const()]
| ^^^^^^^^^^^^^^^
|
= note: see issue #132980 <https://github.com/rust-lang/rust/issues/132980> for more information
= help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: the `#[type_const]` attribute is an experimental feature
--> $DIR/bad-type_const-syntax.rs:11:5
|
LL | #[type_const]
| ^^^^^^^^^^^^^
|
= note: see issue #132980 <https://github.com/rust-lang/rust/issues/132980> for more information
= help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: `#[type_const]` must only be applied to trait associated constants
--> $DIR/bad-type_const-syntax.rs:11:5
|
LL | #[type_const]
| ^^^^^^^^^^^^^
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0658`.

View File

@ -0,0 +1,13 @@
#![feature(min_generic_const_args)]
#![allow(incomplete_features)]
struct S;
impl S {
const N: usize = 42;
}
fn main() {
let _x: [(); S::N] = todo!();
//~^ ERROR inherent associated types are unstable
}

View File

@ -0,0 +1,13 @@
error[E0658]: inherent associated types are unstable
--> $DIR/inherent-const-gating.rs:11:18
|
LL | let _x: [(); S::N] = todo!();
| ^^^^
|
= note: see issue #8995 <https://github.com/rust-lang/rust/issues/8995> for more information
= help: add `#![feature(inherent_associated_types)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0658`.

View File

@ -1,8 +1,10 @@
trait Trait {
#[type_const]
//~^ ERROR experimental
const ASSOC: usize;
}
// FIXME(min_generic_const_args): implement support for this, behind the feature gate
// FIXME(mgca): add suggestion for mgca to this error
fn foo<T: Trait>() -> [u8; <T as Trait>::ASSOC] {
//~^ ERROR generic parameters may not be used in const operations
loop {}

View File

@ -1,5 +1,5 @@
error: generic parameters may not be used in const operations
--> $DIR/feature-gate-min-generic-const-args.rs:6:29
--> $DIR/feature-gate-min-generic-const-args.rs:8:29
|
LL | fn foo<T: Trait>() -> [u8; <T as Trait>::ASSOC] {
| ^ cannot perform const operation using `T`
@ -7,5 +7,16 @@ LL | fn foo<T: Trait>() -> [u8; <T as Trait>::ASSOC] {
= note: type parameters may not be used in const expressions
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
error: aborting due to 1 previous error
error[E0658]: the `#[type_const]` attribute is an experimental feature
--> $DIR/feature-gate-min-generic-const-args.rs:2:5
|
LL | #[type_const]
| ^^^^^^^^^^^^^
|
= note: see issue #132980 <https://github.com/rust-lang/rust/issues/132980> for more information
= help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.