Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lower all trivial const paths as ConstArgKind::Path #135186

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
3de14e3
Start lowering multi-segment const paths as ConstArgKind::Path
camelid Jan 7, 2025
15e9f39
Partially fix parent_args handling for assoc const
camelid Jan 7, 2025
9706c7c
Avoid "const uses param" error
camelid Jan 7, 2025
cd21d8c
Replace TODOs with FIXMEs to allow CI to pass for now
camelid Jan 7, 2025
4dcc15c
Properly lower assoc consts from traits
camelid Jan 8, 2025
e5cf586
Avoid "const depends on generics" error for bare paths under mgca
camelid Jan 9, 2025
b69308e
Standardize mgca FIXMEs to "mgca"
camelid Jan 9, 2025
33c63ae
Start implementing `#[type_const]`
camelid Jan 10, 2025
dd2819f
Allow const paths with generics/qself under mgca
camelid Jan 20, 2025
a912b7d
Fix handling of const qpath args
camelid Jan 23, 2025
0862150
Factor out shared code for lowering assoc item paths
camelid Jan 25, 2025
8f9b82a
Properly handle ambiguous assoc const
camelid Jan 27, 2025
cf5e01e
Factor out shared code for probing inherent assoc items
camelid Jan 27, 2025
07254c2
Factor out shared code for lowering assoc item paths
camelid Jan 27, 2025
c0ed1dd
Relax overly strict mgca requirements
camelid Feb 5, 2025
25a92ee
Clean up (most of) the refactoring
camelid Feb 5, 2025
7d221d5
Bless tests from rebase
camelid Feb 19, 2025
84937e1
Gate mgca codepath for inherent consts under inherent_associated_types
camelid Feb 19, 2025
61c5e74
Move more logic into lower_qpath_shared
camelid Feb 20, 2025
f8a4a65
Reuse existing logic for type aliases
camelid Feb 20, 2025
abe7d68
mgca: Crash on variant const paths for now
camelid Feb 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 16 additions & 11 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,11 @@ 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, .. }])
// FIXME: add docs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:3

#[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())
}
}

Expand Down Expand Up @@ -1177,22 +1178,26 @@ pub struct Expr {
}

impl Expr {
// FIXME: update docs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:3

/// Could this expr be either `N`, or `{ N }`, where `N` is a const parameter.
///
/// If this is not the case, name resolution does not resolve `N` when using
/// `min_const_generics` as more complex expressions are not supported.
///
/// Does not ensure that the path resolves to a const param, 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
}
}
}

Expand Down
18 changes: 9 additions & 9 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1116,7 +1116,8 @@ 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()
// FIXME: should this only allow single-segment paths?
&& path.is_potential_trivial_const_arg(self.tcx.features().min_generic_const_args())
Comment on lines +1119 to +1120
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// FIXME: should this only allow single-segment paths?
&& path.is_potential_trivial_const_arg(self.tcx.features().min_generic_const_args())
&& path.is_potential_trivial_const_arg(false)

Yes I think this should only work for mcg paths rn. Generally this needs to be kept in sync with the logic in name resolution that attempts to resolve type args in both valuens and typens and that currently uses false.

{
debug!(
"lower_generic_arg: Lowering type argument as const argument: {:?}",
Expand Down Expand Up @@ -2083,8 +2084,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, _)))
{
Expand All @@ -2094,7 +2095,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,
);
Expand Down Expand Up @@ -2158,19 +2159,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,
);
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_builtin_macros/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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:
// ==========================================================================
Expand Down
28 changes: 14 additions & 14 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,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;
Expand Down Expand Up @@ -444,21 +445,22 @@ 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,
item_def_id,
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);
Expand Down Expand Up @@ -519,16 +521,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),
}))
}
}

Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
36 changes: 22 additions & 14 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
Expand All @@ -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}"),
Expand All @@ -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}")),
Expand All @@ -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}"),
Expand All @@ -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",
),
Expand Down Expand Up @@ -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>,
Expand Down Expand Up @@ -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
Expand All @@ -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)
),
);
}
};
Expand All @@ -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();
Expand Down Expand Up @@ -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!(
Expand All @@ -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 {
Expand Down Expand Up @@ -1611,7 +1619,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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
Loading
Loading