mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
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:
commit
08db600e8e
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
);
|
||||
|
@ -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",
|
||||
|
@ -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:
|
||||
// ==========================================================================
|
||||
|
@ -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),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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");
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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>> {
|
||||
|
@ -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)]
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
);
|
||||
|
@ -2084,6 +2084,7 @@ symbols! {
|
||||
type_ascribe,
|
||||
type_ascription,
|
||||
type_changing_struct_update,
|
||||
type_const,
|
||||
type_id,
|
||||
type_ir_inherent,
|
||||
type_length_limit,
|
||||
|
@ -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")
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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>`
|
||||
|
@ -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>`
|
||||
|
@ -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>`
|
||||
|
@ -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
|
||||
|
@ -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`
|
||||
|
@ -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`
|
||||
...
|
||||
|
15
tests/ui/const-generics/mgca/ambiguous-assoc-const.rs
Normal file
15
tests/ui/const-generics/mgca/ambiguous-assoc-const.rs
Normal 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() {}
|
15
tests/ui/const-generics/mgca/ambiguous-assoc-const.stderr
Normal file
15
tests/ui/const-generics/mgca/ambiguous-assoc-const.stderr
Normal 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`.
|
@ -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() {}
|
@ -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
|
||||
|
15
tests/ui/const-generics/mgca/assoc-const.rs
Normal file
15
tests/ui/const-generics/mgca/assoc-const.rs
Normal 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() {}
|
17
tests/ui/const-generics/mgca/bad-type_const-syntax.rs
Normal file
17
tests/ui/const-generics/mgca/bad-type_const-syntax.rs
Normal 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() {}
|
35
tests/ui/const-generics/mgca/bad-type_const-syntax.stderr
Normal file
35
tests/ui/const-generics/mgca/bad-type_const-syntax.stderr
Normal 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`.
|
13
tests/ui/const-generics/mgca/inherent-const-gating.rs
Normal file
13
tests/ui/const-generics/mgca/inherent-const-gating.rs
Normal 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
|
||||
}
|
13
tests/ui/const-generics/mgca/inherent-const-gating.stderr
Normal file
13
tests/ui/const-generics/mgca/inherent-const-gating.stderr
Normal 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`.
|
@ -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 {}
|
||||
|
@ -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`.
|
||||
|
Loading…
Reference in New Issue
Block a user