Auto merge of #151144 - JonathanBrouwer:rollup-QW4Ug5q, r=JonathanBrouwer
Rollup of 15 pull requests Successful merges: - rust-lang/rust#150585 (Add a context-consistency check before emitting redundant generic-argument suggestions) - rust-lang/rust#150586 (rustdoc: Fix intra-doc link bugs involving type aliases and associated items) - rust-lang/rust#150590 (Don't try to recover keyword as non-keyword identifier ) - rust-lang/rust#150817 (cleanup: remove borrowck handling for inline const patterns) - rust-lang/rust#150939 (resolve: Relax some asserts in glob overwriting and add tests) - rust-lang/rust#150962 (Remove `FeedConstTy` and provide ty when lowering const arg) - rust-lang/rust#150966 (rustc_target: Remove unused Arch::PowerPC64LE) - rust-lang/rust#150971 (Disallow eii in statement position) - rust-lang/rust#151016 (fix: WASI threading regression by disabling pthread usage) - rust-lang/rust#151046 (compiler: Make Externally Implementable Item (eii) macros "semiopaque") - rust-lang/rust#151099 (Recover parse gracefully from `<const N>`) - rust-lang/rust#151117 (Avoid serde dependency in build_helper when not necessary) - rust-lang/rust#151127 (Delete `MetaItemOrLitParser::Err`) - rust-lang/rust#151128 (Add temporary new bors e-mail address to the mailmap) - rust-lang/rust#151138 (Rename `rust.use-lld` to `rust.bootstrap-override-lld` in INSTALL.md) r? @ghost
This commit is contained in:
commit
b6fdaf2a15
61 changed files with 1156 additions and 626 deletions
1
.mailmap
1
.mailmap
|
|
@ -96,6 +96,7 @@ boolean_coercion <booleancoercion@gmail.com>
|
|||
Boris Egorov <jightuse@gmail.com> <egorov@linux.com>
|
||||
bors <bors@rust-lang.org> bors[bot] <26634292+bors[bot]@users.noreply.github.com>
|
||||
bors <bors@rust-lang.org> bors[bot] <bors[bot]@users.noreply.github.com>
|
||||
bors <bors@rust-lang.org> <122020455+rust-bors[bot]@users.noreply.github.com>
|
||||
BoxyUwU <rust@boxyuwu.dev>
|
||||
BoxyUwU <rust@boxyuwu.dev> <supbscripter@gmail.com>
|
||||
Braden Nelson <moonheart08@users.noreply.github.com>
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ See [the rustc-dev-guide for more info][sysllvm].
|
|||
--set llvm.ninja=false \
|
||||
--set rust.debug-assertions=false \
|
||||
--set rust.jemalloc \
|
||||
--set rust.use-lld=true \
|
||||
--set rust.bootstrap-override-lld=true \
|
||||
--set rust.lto=thin \
|
||||
--set rust.codegen-units=1
|
||||
```
|
||||
|
|
|
|||
|
|
@ -94,7 +94,6 @@ pub fn parse_cfg_entry<S: Stage>(
|
|||
LitKind::Bool(b) => CfgEntry::Bool(b, lit.span),
|
||||
_ => return Err(cx.expected_identifier(lit.span)),
|
||||
},
|
||||
MetaItemOrLitParser::Err(_, err) => return Err(*err),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -514,9 +514,6 @@ impl DocParser {
|
|||
MetaItemOrLitParser::Lit(lit) => {
|
||||
cx.unexpected_literal(lit.span);
|
||||
}
|
||||
MetaItemOrLitParser::Err(..) => {
|
||||
// already had an error here, move on.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -600,9 +597,6 @@ impl DocParser {
|
|||
MetaItemOrLitParser::Lit(lit) => {
|
||||
cx.expected_name_value(lit.span, None);
|
||||
}
|
||||
MetaItemOrLitParser::Err(..) => {
|
||||
// already had an error here, move on.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use rustc_parse::exp;
|
|||
use rustc_parse::parser::{ForceCollect, Parser, PathStyle, token_descr};
|
||||
use rustc_session::errors::{create_lit_error, report_lit_error};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, sym};
|
||||
use rustc_span::{Ident, Span, Symbol, sym};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::ShouldEmit;
|
||||
|
|
@ -192,7 +192,6 @@ impl ArgParser {
|
|||
pub enum MetaItemOrLitParser {
|
||||
MetaItemParser(MetaItemParser),
|
||||
Lit(MetaItemLit),
|
||||
Err(Span, ErrorGuaranteed),
|
||||
}
|
||||
|
||||
impl MetaItemOrLitParser {
|
||||
|
|
@ -210,21 +209,20 @@ impl MetaItemOrLitParser {
|
|||
generic_meta_item_parser.span()
|
||||
}
|
||||
MetaItemOrLitParser::Lit(meta_item_lit) => meta_item_lit.span,
|
||||
MetaItemOrLitParser::Err(span, _) => *span,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lit(&self) -> Option<&MetaItemLit> {
|
||||
match self {
|
||||
MetaItemOrLitParser::Lit(meta_item_lit) => Some(meta_item_lit),
|
||||
_ => None,
|
||||
MetaItemOrLitParser::MetaItemParser(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn meta_item(&self) -> Option<&MetaItemParser> {
|
||||
match self {
|
||||
MetaItemOrLitParser::MetaItemParser(parser) => Some(parser),
|
||||
_ => None,
|
||||
MetaItemOrLitParser::Lit(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ use rustc_infer::infer::{
|
|||
BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin,
|
||||
};
|
||||
use rustc_infer::traits::PredicateObligations;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
|
|
@ -28,7 +29,6 @@ use rustc_middle::ty::{
|
|||
self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CoroutineArgsExt,
|
||||
GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, UserArgs, UserTypeAnnotationIndex, fold_regions,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_mir_dataflow::move_paths::MoveData;
|
||||
use rustc_mir_dataflow::points::DenseLocationMap;
|
||||
use rustc_span::def_id::CRATE_DEF_ID;
|
||||
|
|
@ -387,18 +387,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
#[instrument(skip(self), level = "debug")]
|
||||
fn check_user_type_annotations(&mut self) {
|
||||
debug!(?self.user_type_annotations);
|
||||
let tcx = self.tcx();
|
||||
for user_annotation in self.user_type_annotations {
|
||||
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
|
||||
let annotation = self.instantiate_canonical(span, user_ty);
|
||||
if let ty::UserTypeKind::TypeOf(def, args) = annotation.kind
|
||||
&& let DefKind::InlineConst = tcx.def_kind(def)
|
||||
{
|
||||
assert!(annotation.bounds.is_empty());
|
||||
self.check_inline_const(inferred_ty, def.expect_local(), args, span);
|
||||
} else {
|
||||
self.ascribe_user_type(inferred_ty, annotation, span);
|
||||
}
|
||||
self.ascribe_user_type(inferred_ty, annotation, span);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -560,36 +552,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
self.constraints.liveness_constraints.add_location(region, location);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_inline_const(
|
||||
&mut self,
|
||||
inferred_ty: Ty<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
args: UserArgs<'tcx>,
|
||||
span: Span,
|
||||
) {
|
||||
assert!(args.user_self_ty.is_none());
|
||||
let tcx = self.tcx();
|
||||
let const_ty = tcx.type_of(def_id).instantiate(tcx, args.args);
|
||||
if let Err(terr) =
|
||||
self.eq_types(const_ty, inferred_ty, Locations::All(span), ConstraintCategory::Boring)
|
||||
{
|
||||
span_bug!(
|
||||
span,
|
||||
"bad inline const pattern: ({:?} = {:?}) {:?}",
|
||||
const_ty,
|
||||
inferred_ty,
|
||||
terr
|
||||
);
|
||||
}
|
||||
let args = self.infcx.resolve_vars_if_possible(args.args);
|
||||
let predicates = self.prove_closure_bounds(tcx, def_id, args, Locations::All(span));
|
||||
self.normalize_and_prove_instantiated_predicates(
|
||||
def_id.to_def_id(),
|
||||
predicates,
|
||||
Locations::All(span),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||
|
|
@ -1731,12 +1693,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
let def_id = uv.def;
|
||||
if tcx.def_kind(def_id) == DefKind::InlineConst {
|
||||
let def_id = def_id.expect_local();
|
||||
let predicates = self.prove_closure_bounds(
|
||||
tcx,
|
||||
def_id,
|
||||
uv.args,
|
||||
location.to_locations(),
|
||||
);
|
||||
let predicates = self.prove_closure_bounds(tcx, def_id, uv.args, location);
|
||||
self.normalize_and_prove_instantiated_predicates(
|
||||
def_id.to_def_id(),
|
||||
predicates,
|
||||
|
|
@ -2519,15 +2476,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
// clauses on the struct.
|
||||
AggregateKind::Closure(def_id, args)
|
||||
| AggregateKind::CoroutineClosure(def_id, args)
|
||||
| AggregateKind::Coroutine(def_id, args) => (
|
||||
def_id,
|
||||
self.prove_closure_bounds(
|
||||
tcx,
|
||||
def_id.expect_local(),
|
||||
args,
|
||||
location.to_locations(),
|
||||
),
|
||||
),
|
||||
| AggregateKind::Coroutine(def_id, args) => {
|
||||
(def_id, self.prove_closure_bounds(tcx, def_id.expect_local(), args, location))
|
||||
}
|
||||
|
||||
AggregateKind::Array(_) | AggregateKind::Tuple | AggregateKind::RawPtr(..) => {
|
||||
(CRATE_DEF_ID.to_def_id(), ty::InstantiatedPredicates::empty())
|
||||
|
|
@ -2546,12 +2497,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
args: GenericArgsRef<'tcx>,
|
||||
locations: Locations,
|
||||
location: Location,
|
||||
) -> ty::InstantiatedPredicates<'tcx> {
|
||||
let root_def_id = self.root_cx.root_def_id();
|
||||
// We will have to handle propagated closure requirements for this closure,
|
||||
// but need to defer this until the nested body has been fully borrow checked.
|
||||
self.deferred_closure_requirements.push((def_id, args, locations));
|
||||
self.deferred_closure_requirements.push((def_id, args, location.to_locations()));
|
||||
|
||||
// Equate closure args to regions inherited from `root_def_id`. Fixes #98589.
|
||||
let typeck_root_args = ty::GenericArgs::identity_for_item(tcx, root_def_id);
|
||||
|
|
@ -2575,7 +2526,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
if let Err(_) = self.eq_args(
|
||||
typeck_root_args,
|
||||
parent_args,
|
||||
locations,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::BoringNoLocation,
|
||||
) {
|
||||
span_mirbug!(
|
||||
|
|
|
|||
|
|
@ -161,6 +161,8 @@ builtin_macros_eii_only_once = `#[{$name}]` can only be specified once
|
|||
|
||||
builtin_macros_eii_shared_macro_expected_function = `#[{$name}]` is only valid on functions
|
||||
builtin_macros_eii_shared_macro_expected_max_one_argument = `#[{$name}]` expected no arguments or a single argument: `#[{$name}(default)]`
|
||||
builtin_macros_eii_shared_macro_in_statement_position = `#[{$name}]` can only be used on functions inside a module
|
||||
.label = `#[{$name}]` is used on this item, which is part of another item's local scope
|
||||
|
||||
builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time
|
||||
.cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
use rustc_ast::token::{Delimiter, TokenKind};
|
||||
use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
|
||||
use rustc_ast::{
|
||||
Attribute, DUMMY_NODE_ID, EiiDecl, EiiImpl, ItemKind, MetaItem, Path, Stmt, StmtKind,
|
||||
Visibility, ast,
|
||||
Attribute, DUMMY_NODE_ID, EiiDecl, EiiImpl, ItemKind, MetaItem, Path, StmtKind, Visibility, ast,
|
||||
};
|
||||
use rustc_ast_pretty::pprust::path_to_string;
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
|
|
@ -12,6 +11,7 @@ use thin_vec::{ThinVec, thin_vec};
|
|||
use crate::errors::{
|
||||
EiiExternTargetExpectedList, EiiExternTargetExpectedMacro, EiiExternTargetExpectedUnsafe,
|
||||
EiiMacroExpectedMaxOneArgument, EiiOnlyOnce, EiiSharedMacroExpectedFunction,
|
||||
EiiSharedMacroInStatementPosition,
|
||||
};
|
||||
|
||||
/// ```rust
|
||||
|
|
@ -55,29 +55,29 @@ fn eii_(
|
|||
ecx: &mut ExtCtxt<'_>,
|
||||
eii_attr_span: Span,
|
||||
meta_item: &ast::MetaItem,
|
||||
item: Annotatable,
|
||||
orig_item: Annotatable,
|
||||
impl_unsafe: bool,
|
||||
) -> Vec<Annotatable> {
|
||||
let eii_attr_span = ecx.with_def_site_ctxt(eii_attr_span);
|
||||
|
||||
let (item, wrap_item): (_, &dyn Fn(_) -> _) = if let Annotatable::Item(item) = item {
|
||||
(item, &Annotatable::Item)
|
||||
} else if let Annotatable::Stmt(ref stmt) = item
|
||||
let item = if let Annotatable::Item(item) = orig_item {
|
||||
item
|
||||
} else if let Annotatable::Stmt(ref stmt) = orig_item
|
||||
&& let StmtKind::Item(ref item) = stmt.kind
|
||||
&& let ItemKind::Fn(ref f) = item.kind
|
||||
{
|
||||
(item.clone(), &|item| {
|
||||
Annotatable::Stmt(Box::new(Stmt {
|
||||
id: DUMMY_NODE_ID,
|
||||
kind: StmtKind::Item(item),
|
||||
span: eii_attr_span,
|
||||
}))
|
||||
})
|
||||
ecx.dcx().emit_err(EiiSharedMacroInStatementPosition {
|
||||
span: eii_attr_span.to(item.span),
|
||||
name: path_to_string(&meta_item.path),
|
||||
item_span: f.ident.span,
|
||||
});
|
||||
return vec![orig_item];
|
||||
} else {
|
||||
ecx.dcx().emit_err(EiiSharedMacroExpectedFunction {
|
||||
span: eii_attr_span,
|
||||
name: path_to_string(&meta_item.path),
|
||||
});
|
||||
return vec![item];
|
||||
return vec![orig_item];
|
||||
};
|
||||
|
||||
let ast::Item { attrs, id: _, span: _, vis, kind: ItemKind::Fn(func), tokens: _ } =
|
||||
|
|
@ -87,7 +87,7 @@ fn eii_(
|
|||
span: eii_attr_span,
|
||||
name: path_to_string(&meta_item.path),
|
||||
});
|
||||
return vec![wrap_item(item)];
|
||||
return vec![Annotatable::Item(item)];
|
||||
};
|
||||
// only clone what we need
|
||||
let attrs = attrs.clone();
|
||||
|
|
@ -98,17 +98,19 @@ fn eii_(
|
|||
filter_attrs_for_multiple_eii_attr(ecx, attrs, eii_attr_span, &meta_item.path);
|
||||
|
||||
let Ok(macro_name) = name_for_impl_macro(ecx, &func, &meta_item) else {
|
||||
return vec![wrap_item(item)];
|
||||
// we don't need to wrap in Annotatable::Stmt conditionally since
|
||||
// EII can't be used on items in statement position
|
||||
return vec![Annotatable::Item(item)];
|
||||
};
|
||||
|
||||
// span of the declaring item without attributes
|
||||
let item_span = func.sig.span;
|
||||
let foreign_item_name = func.ident;
|
||||
|
||||
let mut return_items = Vec::new();
|
||||
let mut module_items = Vec::new();
|
||||
|
||||
if func.body.is_some() {
|
||||
return_items.push(generate_default_impl(
|
||||
module_items.push(generate_default_impl(
|
||||
ecx,
|
||||
&func,
|
||||
impl_unsafe,
|
||||
|
|
@ -119,7 +121,7 @@ fn eii_(
|
|||
))
|
||||
}
|
||||
|
||||
return_items.push(generate_foreign_item(
|
||||
module_items.push(generate_foreign_item(
|
||||
ecx,
|
||||
eii_attr_span,
|
||||
item_span,
|
||||
|
|
@ -127,7 +129,7 @@ fn eii_(
|
|||
vis,
|
||||
&attrs_from_decl,
|
||||
));
|
||||
return_items.push(generate_attribute_macro_to_implement(
|
||||
module_items.push(generate_attribute_macro_to_implement(
|
||||
ecx,
|
||||
eii_attr_span,
|
||||
macro_name,
|
||||
|
|
@ -136,7 +138,9 @@ fn eii_(
|
|||
&attrs_from_decl,
|
||||
));
|
||||
|
||||
return_items.into_iter().map(wrap_item).collect()
|
||||
// we don't need to wrap in Annotatable::Stmt conditionally since
|
||||
// EII can't be used on items in statement position
|
||||
module_items.into_iter().map(Annotatable::Item).collect()
|
||||
}
|
||||
|
||||
/// Decide on the name of the macro that can be used to implement the EII.
|
||||
|
|
@ -213,29 +217,14 @@ fn generate_default_impl(
|
|||
known_eii_macro_resolution: Some(ast::EiiDecl {
|
||||
foreign_item: ecx.path(
|
||||
foreign_item_name.span,
|
||||
// prefix super to escape the `dflt` module generated below
|
||||
vec![Ident::from_str_and_span("super", foreign_item_name.span), foreign_item_name],
|
||||
// prefix self to explicitly escape the const block generated below
|
||||
// NOTE: this is why EIIs can't be used on statements
|
||||
vec![Ident::from_str_and_span("self", foreign_item_name.span), foreign_item_name],
|
||||
),
|
||||
impl_unsafe,
|
||||
}),
|
||||
});
|
||||
|
||||
let item_mod = |span: Span, name: Ident, items: ThinVec<Box<ast::Item>>| {
|
||||
ecx.item(
|
||||
item_span,
|
||||
ThinVec::new(),
|
||||
ItemKind::Mod(
|
||||
ast::Safety::Default,
|
||||
name,
|
||||
ast::ModKind::Loaded(
|
||||
items,
|
||||
ast::Inline::Yes,
|
||||
ast::ModSpans { inner_span: span, inject_use_span: span },
|
||||
),
|
||||
),
|
||||
)
|
||||
};
|
||||
|
||||
let anon_mod = |span: Span, stmts: ThinVec<ast::Stmt>| {
|
||||
let unit = ecx.ty(item_span, ast::TyKind::Tup(ThinVec::new()));
|
||||
let underscore = Ident::new(kw::Underscore, item_span);
|
||||
|
|
@ -248,33 +237,13 @@ fn generate_default_impl(
|
|||
};
|
||||
|
||||
// const _: () = {
|
||||
// mod dflt {
|
||||
// use super::*;
|
||||
// <orig fn>
|
||||
// }
|
||||
// <orig fn>
|
||||
// }
|
||||
anon_mod(
|
||||
item_span,
|
||||
thin_vec![ecx.stmt_item(
|
||||
item_span,
|
||||
item_mod(
|
||||
item_span,
|
||||
Ident::from_str_and_span("dflt", item_span),
|
||||
thin_vec![
|
||||
ecx.item(
|
||||
item_span,
|
||||
thin_vec![ecx.attr_nested_word(sym::allow, sym::unused_imports, item_span)],
|
||||
ItemKind::Use(ast::UseTree {
|
||||
prefix: ast::Path::from_ident(Ident::from_str_and_span(
|
||||
"super", item_span,
|
||||
)),
|
||||
kind: ast::UseTreeKind::Glob,
|
||||
span: item_span,
|
||||
})
|
||||
),
|
||||
ecx.item(item_span, attrs, ItemKind::Fn(Box::new(default_func)))
|
||||
]
|
||||
)
|
||||
ecx.item(item_span, attrs, ItemKind::Fn(Box::new(default_func)))
|
||||
),],
|
||||
)
|
||||
}
|
||||
|
|
@ -366,6 +335,9 @@ fn generate_attribute_macro_to_implement(
|
|||
// errors for eii's in std.
|
||||
macro_attrs.extend_from_slice(attrs_from_decl);
|
||||
|
||||
// Avoid "missing stability attribute" errors for eiis in std. See #146993.
|
||||
macro_attrs.push(ecx.attr_name_value_str(sym::rustc_macro_transparency, sym::semiopaque, span));
|
||||
|
||||
// #[builtin_macro(eii_shared_macro)]
|
||||
macro_attrs.push(ecx.attr_nested_word(sym::rustc_builtin_macro, sym::eii_shared_macro, span));
|
||||
|
||||
|
|
|
|||
|
|
@ -1039,6 +1039,16 @@ pub(crate) struct EiiSharedMacroExpectedFunction {
|
|||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_eii_shared_macro_in_statement_position)]
|
||||
pub(crate) struct EiiSharedMacroInStatementPosition {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub name: String,
|
||||
#[label]
|
||||
pub item_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_eii_only_once)]
|
||||
pub(crate) struct EiiOnlyOnce {
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ impl CodegenCx<'_, '_> {
|
|||
}
|
||||
|
||||
// PowerPC64 prefers TOC indirection to avoid copy relocations.
|
||||
if matches!(self.tcx.sess.target.arch, Arch::PowerPC64 | Arch::PowerPC64LE) {
|
||||
if self.tcx.sess.target.arch == Arch::PowerPC64 {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1064,15 +1064,6 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
|
|||
AllowHigherAlign::Yes,
|
||||
ForceRightAdjust::Yes,
|
||||
),
|
||||
Arch::PowerPC64LE => emit_ptr_va_arg(
|
||||
bx,
|
||||
addr,
|
||||
target_ty,
|
||||
PassMode::Direct,
|
||||
SlotSize::Bytes8,
|
||||
AllowHigherAlign::Yes,
|
||||
ForceRightAdjust::No,
|
||||
),
|
||||
Arch::LoongArch32 => emit_ptr_va_arg(
|
||||
bx,
|
||||
addr,
|
||||
|
|
|
|||
|
|
@ -47,9 +47,7 @@ use rustc_trait_selection::traits::{
|
|||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::errors;
|
||||
use crate::hir_ty_lowering::{
|
||||
FeedConstTy, HirTyLowerer, InherentAssocCandidate, RegionInferReason,
|
||||
};
|
||||
use crate::hir_ty_lowering::{HirTyLowerer, InherentAssocCandidate, RegionInferReason};
|
||||
|
||||
pub(crate) mod dump;
|
||||
mod generics_of;
|
||||
|
|
@ -1499,7 +1497,7 @@ fn const_param_default<'tcx>(
|
|||
|
||||
let ct = icx
|
||||
.lowerer()
|
||||
.lower_const_arg(default_ct, FeedConstTy::with_type_of(tcx, def_id, identity_args));
|
||||
.lower_const_arg(default_ct, tcx.type_of(def_id).instantiate(tcx, identity_args));
|
||||
ty::EarlyBinder::bind(ct)
|
||||
}
|
||||
|
||||
|
|
@ -1557,7 +1555,7 @@ fn const_of_item<'tcx>(
|
|||
let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id);
|
||||
let ct = icx
|
||||
.lowerer()
|
||||
.lower_const_arg(ct_arg, FeedConstTy::with_type_of(tcx, def_id.to_def_id(), identity_args));
|
||||
.lower_const_arg(ct_arg, tcx.type_of(def_id.to_def_id()).instantiate(tcx, identity_args));
|
||||
if let Err(e) = icx.check_tainted_by_errors()
|
||||
&& !ct.references_error()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -988,6 +988,9 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
|||
gen_arg_spans[self.num_expected_type_or_const_args() - 1]
|
||||
};
|
||||
let span_hi_redundant_type_or_const_args = gen_arg_spans[gen_arg_spans.len() - 1];
|
||||
if !span_lo_redundant_type_or_const_args.eq_ctxt(span_hi_redundant_type_or_const_args) {
|
||||
return;
|
||||
}
|
||||
let span_redundant_type_or_const_args = span_lo_redundant_type_or_const_args
|
||||
.shrink_to_hi()
|
||||
.to(span_hi_redundant_type_or_const_args);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ use tracing::{debug, instrument};
|
|||
|
||||
use crate::errors;
|
||||
use crate::hir_ty_lowering::{
|
||||
AssocItemQSelf, FeedConstTy, GenericsArgsErrExtend, HirTyLowerer, ImpliedBoundsContext,
|
||||
AssocItemQSelf, GenericsArgsErrExtend, HirTyLowerer, ImpliedBoundsContext,
|
||||
OverlappingAsssocItemConstraints, PredicateFilter, RegionInferReason,
|
||||
};
|
||||
|
||||
|
|
@ -510,7 +510,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// Create the generic arguments for the associated type or constant by joining the
|
||||
// parent arguments (the arguments of the trait) and the own arguments (the ones of
|
||||
// the associated item itself) and construct an alias type using them.
|
||||
let alias_term = candidate.map_bound(|trait_ref| {
|
||||
candidate.map_bound(|trait_ref| {
|
||||
let item_segment = hir::PathSegment {
|
||||
ident: constraint.ident,
|
||||
hir_id: constraint.hir_id,
|
||||
|
|
@ -528,20 +528,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
debug!(?alias_args);
|
||||
|
||||
ty::AliasTerm::new_from_args(tcx, assoc_item.def_id, alias_args)
|
||||
});
|
||||
|
||||
// Provide the resolved type of the associated constant to `type_of(AnonConst)`.
|
||||
if let Some(const_arg) = constraint.ct()
|
||||
&& let hir::ConstArgKind::Anon(anon_const) = const_arg.kind
|
||||
{
|
||||
let ty = alias_term
|
||||
.map_bound(|alias| tcx.type_of(alias.def_id).instantiate(tcx, alias.args));
|
||||
let ty =
|
||||
check_assoc_const_binding_type(self, constraint.ident, ty, constraint.hir_id);
|
||||
tcx.feed_anon_const_type(anon_const.def_id, ty::EarlyBinder::bind(ty));
|
||||
}
|
||||
|
||||
alias_term
|
||||
})
|
||||
};
|
||||
|
||||
match constraint.kind {
|
||||
|
|
@ -555,7 +542,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
hir::AssocItemConstraintKind::Equality { term } => {
|
||||
let term = match term {
|
||||
hir::Term::Ty(ty) => self.lower_ty(ty).into(),
|
||||
hir::Term::Const(ct) => self.lower_const_arg(ct, FeedConstTy::No).into(),
|
||||
hir::Term::Const(ct) => {
|
||||
let ty = projection_term.map_bound(|alias| {
|
||||
tcx.type_of(alias.def_id).instantiate(tcx, alias.args)
|
||||
});
|
||||
let ty = check_assoc_const_binding_type(
|
||||
self,
|
||||
constraint.ident,
|
||||
ty,
|
||||
constraint.hir_id,
|
||||
);
|
||||
|
||||
self.lower_const_arg(ct, ty).into()
|
||||
}
|
||||
};
|
||||
|
||||
// Find any late-bound regions declared in `ty` that are not
|
||||
|
|
@ -871,7 +870,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
/// probably gate this behind another feature flag.
|
||||
///
|
||||
/// [^1]: <https://github.com/rust-lang/project-const-generics/issues/28>.
|
||||
fn check_assoc_const_binding_type<'tcx>(
|
||||
pub(crate) fn check_assoc_const_binding_type<'tcx>(
|
||||
cx: &dyn HirTyLowerer<'tcx>,
|
||||
assoc_const: Ident,
|
||||
ty: ty::Binder<'tcx, Ty<'tcx>>,
|
||||
|
|
|
|||
|
|
@ -253,35 +253,6 @@ impl AssocItemQSelf {
|
|||
}
|
||||
}
|
||||
|
||||
/// In some cases, [`hir::ConstArg`]s that are being used in the type system
|
||||
/// through const generics need to have their type "fed" to them
|
||||
/// using the query system.
|
||||
///
|
||||
/// Use this enum with `<dyn HirTyLowerer>::lower_const_arg` to instruct it with the
|
||||
/// desired behavior.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum FeedConstTy<'tcx> {
|
||||
/// Feed the type to the (anno) const arg.
|
||||
WithTy(Ty<'tcx>),
|
||||
/// Don't feed the type.
|
||||
No,
|
||||
}
|
||||
|
||||
impl<'tcx> FeedConstTy<'tcx> {
|
||||
/// The `DefId` belongs to the const param that we are supplying
|
||||
/// this (anon) const arg to.
|
||||
///
|
||||
/// The list of generic args is used to instantiate the parameters
|
||||
/// used by the type of the const param specified by `DefId`.
|
||||
pub fn with_type_of(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
generic_args: &[ty::GenericArg<'tcx>],
|
||||
) -> Self {
|
||||
Self::WithTy(tcx.type_of(def_id).instantiate(tcx, generic_args))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum LowerTypeRelativePathMode {
|
||||
Type(PermitVariants),
|
||||
|
|
@ -733,7 +704,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// Ambig portions of `ConstArg` are handled in the match arm below
|
||||
.lower_const_arg(
|
||||
ct.as_unambig_ct(),
|
||||
FeedConstTy::with_type_of(tcx, param.def_id, preceding_args),
|
||||
tcx.type_of(param.def_id).instantiate(tcx, preceding_args),
|
||||
)
|
||||
.into(),
|
||||
(&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
|
||||
|
|
@ -1269,10 +1240,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let mut where_bounds = vec![];
|
||||
for bound in [bound, bound2].into_iter().chain(matching_candidates) {
|
||||
let bound_id = bound.def_id();
|
||||
let bound_span = tcx
|
||||
.associated_items(bound_id)
|
||||
.find_by_ident_and_kind(tcx, assoc_ident, assoc_tag, bound_id)
|
||||
.and_then(|item| tcx.hir_span_if_local(item.def_id));
|
||||
let assoc_item = tcx.associated_items(bound_id).find_by_ident_and_kind(
|
||||
tcx,
|
||||
assoc_ident,
|
||||
assoc_tag,
|
||||
bound_id,
|
||||
);
|
||||
let bound_span = assoc_item.and_then(|item| tcx.hir_span_if_local(item.def_id));
|
||||
|
||||
if let Some(bound_span) = bound_span {
|
||||
err.span_label(
|
||||
|
|
@ -1285,7 +1259,43 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let term: ty::Term<'_> = match term {
|
||||
hir::Term::Ty(ty) => self.lower_ty(ty).into(),
|
||||
hir::Term::Const(ct) => {
|
||||
self.lower_const_arg(ct, FeedConstTy::No).into()
|
||||
let assoc_item =
|
||||
assoc_item.expect("assoc_item should be present");
|
||||
let projection_term = bound.map_bound(|trait_ref| {
|
||||
let item_segment = hir::PathSegment {
|
||||
ident: constraint.ident,
|
||||
hir_id: constraint.hir_id,
|
||||
res: Res::Err,
|
||||
args: Some(constraint.gen_args),
|
||||
infer_args: false,
|
||||
};
|
||||
|
||||
let alias_args = self.lower_generic_args_of_assoc_item(
|
||||
constraint.ident.span,
|
||||
assoc_item.def_id,
|
||||
&item_segment,
|
||||
trait_ref.args,
|
||||
);
|
||||
ty::AliasTerm::new_from_args(
|
||||
tcx,
|
||||
assoc_item.def_id,
|
||||
alias_args,
|
||||
)
|
||||
});
|
||||
|
||||
// FIXME(mgca): code duplication with other places we lower
|
||||
// the rhs' of associated const bindings
|
||||
let ty = projection_term.map_bound(|alias| {
|
||||
tcx.type_of(alias.def_id).instantiate(tcx, alias.args)
|
||||
});
|
||||
let ty = bounds::check_assoc_const_binding_type(
|
||||
self,
|
||||
constraint.ident,
|
||||
ty,
|
||||
constraint.hir_id,
|
||||
);
|
||||
|
||||
self.lower_const_arg(ct, ty).into()
|
||||
}
|
||||
};
|
||||
if term.references_error() {
|
||||
|
|
@ -2310,16 +2320,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
/// Lower a [`hir::ConstArg`] to a (type-level) [`ty::Const`](Const).
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn lower_const_arg(
|
||||
&self,
|
||||
const_arg: &hir::ConstArg<'tcx>,
|
||||
feed: FeedConstTy<'tcx>,
|
||||
) -> Const<'tcx> {
|
||||
pub fn lower_const_arg(&self, const_arg: &hir::ConstArg<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
if let FeedConstTy::WithTy(anon_const_type) = feed
|
||||
&& let hir::ConstArgKind::Anon(anon) = &const_arg.kind
|
||||
{
|
||||
if let hir::ConstArgKind::Anon(anon) = &const_arg.kind {
|
||||
// FIXME(generic_const_parameter_types): Ideally we remove these errors below when
|
||||
// we have the ability to intermix typeck of anon const const args with the parent
|
||||
// bodies typeck.
|
||||
|
|
@ -2329,7 +2333,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// hir typeck was using equality but mir borrowck wound up using subtyping as that could
|
||||
// result in a non-infer in hir typeck but a region variable in borrowck.
|
||||
if tcx.features().generic_const_parameter_types()
|
||||
&& (anon_const_type.has_free_regions() || anon_const_type.has_erased_regions())
|
||||
&& (ty.has_free_regions() || ty.has_erased_regions())
|
||||
{
|
||||
let e = self.dcx().span_err(
|
||||
const_arg.span,
|
||||
|
|
@ -2341,7 +2345,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// We must error if the instantiated type has any inference variables as we will
|
||||
// use this type to feed the `type_of` and query results must not contain inference
|
||||
// variables otherwise we will ICE.
|
||||
if anon_const_type.has_non_region_infer() {
|
||||
if ty.has_non_region_infer() {
|
||||
let e = self.dcx().span_err(
|
||||
const_arg.span,
|
||||
"anonymous constants with inferred types are not yet supported",
|
||||
|
|
@ -2351,7 +2355,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
// We error when the type contains unsubstituted generics since we do not currently
|
||||
// give the anon const any of the generics from the parent.
|
||||
if anon_const_type.has_non_region_param() {
|
||||
if ty.has_non_region_param() {
|
||||
let e = self.dcx().span_err(
|
||||
const_arg.span,
|
||||
"anonymous constants referencing generics are not yet supported",
|
||||
|
|
@ -2360,12 +2364,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
return ty::Const::new_error(tcx, e);
|
||||
}
|
||||
|
||||
tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(anon_const_type));
|
||||
tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(ty));
|
||||
}
|
||||
|
||||
let hir_id = const_arg.hir_id;
|
||||
match const_arg.kind {
|
||||
hir::ConstArgKind::Tup(exprs) => self.lower_const_arg_tup(exprs, feed, const_arg.span),
|
||||
hir::ConstArgKind::Tup(exprs) => self.lower_const_arg_tup(exprs, ty, const_arg.span),
|
||||
hir::ConstArgKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
|
||||
debug!(?maybe_qself, ?path);
|
||||
let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
|
||||
|
|
@ -2389,16 +2393,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
hir::ConstArgKind::TupleCall(qpath, args) => {
|
||||
self.lower_const_arg_tuple_call(hir_id, qpath, args, const_arg.span)
|
||||
}
|
||||
hir::ConstArgKind::Array(array_expr) => self.lower_const_arg_array(array_expr, feed),
|
||||
hir::ConstArgKind::Array(array_expr) => self.lower_const_arg_array(array_expr, ty),
|
||||
hir::ConstArgKind::Anon(anon) => self.lower_const_arg_anon(anon),
|
||||
hir::ConstArgKind::Infer(()) => self.ct_infer(None, const_arg.span),
|
||||
hir::ConstArgKind::Error(e) => ty::Const::new_error(tcx, e),
|
||||
hir::ConstArgKind::Literal(kind) if let FeedConstTy::WithTy(anon_const_type) = feed => {
|
||||
self.lower_const_arg_literal(&kind, anon_const_type, const_arg.span)
|
||||
}
|
||||
hir::ConstArgKind::Literal(..) => {
|
||||
let e = self.dcx().span_err(const_arg.span, "literal of unknown type");
|
||||
ty::Const::new_error(tcx, e)
|
||||
hir::ConstArgKind::Literal(kind) => {
|
||||
self.lower_const_arg_literal(&kind, ty, const_arg.span)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2406,14 +2406,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
fn lower_const_arg_array(
|
||||
&self,
|
||||
array_expr: &'tcx hir::ConstArgArrayExpr<'tcx>,
|
||||
feed: FeedConstTy<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Const<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
let FeedConstTy::WithTy(ty) = feed else {
|
||||
return Const::new_error_with_message(tcx, array_expr.span, "unsupported const array");
|
||||
};
|
||||
|
||||
let ty::Array(elem_ty, _) = ty.kind() else {
|
||||
let e = tcx
|
||||
.dcx()
|
||||
|
|
@ -2424,7 +2420,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let elems = array_expr
|
||||
.elems
|
||||
.iter()
|
||||
.map(|elem| self.lower_const_arg(elem, FeedConstTy::WithTy(*elem_ty)))
|
||||
.map(|elem| self.lower_const_arg(elem, *elem_ty))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let valtree = ty::ValTree::from_branches(tcx, elems);
|
||||
|
|
@ -2507,7 +2503,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.iter()
|
||||
.zip(args)
|
||||
.map(|(field_def, arg)| {
|
||||
self.lower_const_arg(arg, FeedConstTy::with_type_of(tcx, field_def.did, adt_args))
|
||||
self.lower_const_arg(arg, tcx.type_of(field_def.did).instantiate(tcx, adt_args))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
|
@ -2526,15 +2522,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
fn lower_const_arg_tup(
|
||||
&self,
|
||||
exprs: &'tcx [&'tcx hir::ConstArg<'tcx>],
|
||||
feed: FeedConstTy<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
) -> Const<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
let FeedConstTy::WithTy(ty) = feed else {
|
||||
return Const::new_error_with_message(tcx, span, "const tuple lack type information");
|
||||
};
|
||||
|
||||
let ty::Tuple(tys) = ty.kind() else {
|
||||
let e = tcx.dcx().span_err(span, format!("expected `{}`, found const tuple", ty));
|
||||
return Const::new_error(tcx, e);
|
||||
|
|
@ -2543,7 +2535,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let exprs = exprs
|
||||
.iter()
|
||||
.zip(tys.iter())
|
||||
.map(|(expr, ty)| self.lower_const_arg(expr, FeedConstTy::WithTy(ty)))
|
||||
.map(|(expr, ty)| self.lower_const_arg(expr, ty))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let valtree = ty::ValTree::from_branches(tcx, exprs);
|
||||
|
|
@ -2630,7 +2622,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
self.lower_const_arg(
|
||||
expr.expr,
|
||||
FeedConstTy::with_type_of(tcx, field_def.did, adt_args),
|
||||
tcx.type_of(field_def.did).instantiate(tcx, adt_args),
|
||||
)
|
||||
}
|
||||
None => {
|
||||
|
|
@ -2992,7 +2984,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.unwrap_or_else(|guar| Ty::new_error(tcx, guar))
|
||||
}
|
||||
hir::TyKind::Array(ty, length) => {
|
||||
let length = self.lower_const_arg(length, FeedConstTy::No);
|
||||
let length = self.lower_const_arg(length, tcx.types.usize);
|
||||
Ty::new_array_with_const_len(tcx, self.lower_ty(ty), length)
|
||||
}
|
||||
hir::TyKind::Infer(()) => {
|
||||
|
|
@ -3032,8 +3024,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// Keep this list of types in sync with the list of types that
|
||||
// the `RangePattern` trait is implemented for.
|
||||
ty::Int(_) | ty::Uint(_) | ty::Char => {
|
||||
let start = self.lower_const_arg(start, FeedConstTy::No);
|
||||
let end = self.lower_const_arg(end, FeedConstTy::No);
|
||||
let start = self.lower_const_arg(start, ty);
|
||||
let end = self.lower_const_arg(end, ty);
|
||||
Ok(ty::PatternKind::Range { start, end })
|
||||
}
|
||||
_ => Err(self
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ use rustc_span::{ErrorGuaranteed, Span};
|
|||
use rustc_trait_selection::traits;
|
||||
|
||||
pub use crate::collect::suggest_impl_trait;
|
||||
use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer};
|
||||
use crate::hir_ty_lowering::HirTyLowerer;
|
||||
|
||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||
|
||||
|
|
@ -301,8 +301,8 @@ pub fn lower_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
|
|||
pub fn lower_const_arg_for_rustdoc<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
hir_ct: &hir::ConstArg<'tcx>,
|
||||
feed: FeedConstTy<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Const<'tcx> {
|
||||
let env_def_id = tcx.hir_get_parent_item(hir_ct.hir_id);
|
||||
collect::ItemCtxt::new(tcx, env_def_id.def_id).lowerer().lower_const_arg(hir_ct, feed)
|
||||
collect::ItemCtxt::new(tcx, env_def_id.def_id).lowerer().lower_const_arg(hir_ct, ty)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{ExprKind, HirId, QPath, find_attr, is_range_literal};
|
||||
use rustc_hir_analysis::NoVariantNamed;
|
||||
use rustc_hir_analysis::hir_ty_lowering::{FeedConstTy, HirTyLowerer as _};
|
||||
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer as _;
|
||||
use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk, RegionVariableOrigin};
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
|
||||
|
|
@ -1749,7 +1749,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let count_span = count.span;
|
||||
let count = self.try_structurally_resolve_const(
|
||||
count_span,
|
||||
self.normalize(count_span, self.lower_const_arg(count, FeedConstTy::No)),
|
||||
self.normalize(count_span, self.lower_const_arg(count, tcx.types.usize)),
|
||||
);
|
||||
|
||||
if let Some(count) = count.try_to_target_usize(tcx) {
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ use rustc_hir_analysis::hir_ty_lowering::generics::{
|
|||
check_generic_arg_count_for_call, lower_generic_args,
|
||||
};
|
||||
use rustc_hir_analysis::hir_ty_lowering::{
|
||||
ExplicitLateBound, FeedConstTy, GenericArgCountMismatch, GenericArgCountResult,
|
||||
GenericArgsLowerer, GenericPathSegment, HirTyLowerer, IsMethodCall, RegionInferReason,
|
||||
ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgsLowerer,
|
||||
GenericPathSegment, HirTyLowerer, IsMethodCall, RegionInferReason,
|
||||
};
|
||||
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
|
||||
use rustc_infer::infer::{DefineOpaqueTypes, InferResult};
|
||||
|
|
@ -525,9 +525,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
pub(crate) fn lower_const_arg(
|
||||
&self,
|
||||
const_arg: &'tcx hir::ConstArg<'tcx>,
|
||||
feed: FeedConstTy<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> ty::Const<'tcx> {
|
||||
let ct = self.lowerer().lower_const_arg(const_arg, feed);
|
||||
let ct = self.lowerer().lower_const_arg(const_arg, ty);
|
||||
self.register_wf_obligation(
|
||||
ct.into(),
|
||||
self.tcx.hir_span(const_arg.hir_id),
|
||||
|
|
@ -1228,7 +1228,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// Ambiguous parts of `ConstArg` are handled in the match arms below
|
||||
.lower_const_arg(
|
||||
ct.as_unambig_ct(),
|
||||
FeedConstTy::with_type_of(self.fcx.tcx, param.def_id, preceding_args),
|
||||
self.fcx
|
||||
.tcx
|
||||
.type_of(param.def_id)
|
||||
.instantiate(self.fcx.tcx, preceding_args),
|
||||
)
|
||||
.into(),
|
||||
(&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use rustc_hir_analysis::hir_ty_lowering::generics::{
|
|||
check_generic_arg_count_for_call, lower_generic_args,
|
||||
};
|
||||
use rustc_hir_analysis::hir_ty_lowering::{
|
||||
FeedConstTy, GenericArgsLowerer, HirTyLowerer, IsMethodCall, RegionInferReason,
|
||||
GenericArgsLowerer, HirTyLowerer, IsMethodCall, RegionInferReason,
|
||||
};
|
||||
use rustc_infer::infer::{
|
||||
BoundRegionConversionTime, DefineOpaqueTypes, InferOk, RegionVariableOrigin,
|
||||
|
|
@ -447,7 +447,10 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
|||
// We handle the ambig portions of `ConstArg` in the match arms below
|
||||
.lower_const_arg(
|
||||
ct.as_unambig_ct(),
|
||||
FeedConstTy::with_type_of(self.cfcx.tcx, param.def_id, preceding_args),
|
||||
self.cfcx
|
||||
.tcx
|
||||
.type_of(param.def_id)
|
||||
.instantiate(self.cfcx.tcx, preceding_args),
|
||||
)
|
||||
.into(),
|
||||
(GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
|
||||
|
|
|
|||
|
|
@ -109,7 +109,31 @@ impl<'a> Parser<'a> {
|
|||
|
||||
self.expect_keyword(exp!(Const))?;
|
||||
let ident = self.parse_ident()?;
|
||||
self.expect(exp!(Colon))?;
|
||||
if let Err(mut err) = self.expect(exp!(Colon)) {
|
||||
return if self.token.kind == token::Comma || self.token.kind == token::Gt {
|
||||
// Recover parse from `<const N>` where the type is missing.
|
||||
let span = const_span.to(ident.span);
|
||||
err.span_suggestion_verbose(
|
||||
ident.span.shrink_to_hi(),
|
||||
"you likely meant to write the type of the const parameter here",
|
||||
": /* Type */".to_string(),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
let kind = TyKind::Err(err.emit());
|
||||
let ty = self.mk_ty(span, kind);
|
||||
Ok(GenericParam {
|
||||
ident,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
attrs: preceding_attrs,
|
||||
bounds: Vec::new(),
|
||||
kind: GenericParamKind::Const { ty, span, default: None },
|
||||
is_placeholder: false,
|
||||
colon_span: None,
|
||||
})
|
||||
} else {
|
||||
Err(err)
|
||||
};
|
||||
}
|
||||
let ty = self.parse_ty()?;
|
||||
|
||||
// Parse optional const generics default value.
|
||||
|
|
|
|||
|
|
@ -408,6 +408,7 @@ impl<'a> Parser<'a> {
|
|||
let insert_span = ident_span.shrink_to_lo();
|
||||
|
||||
let ident = if self.token.is_ident()
|
||||
&& self.token.is_non_reserved_ident()
|
||||
&& (!is_const || self.look_ahead(1, |t| *t == token::OpenParen))
|
||||
&& self.look_ahead(1, |t| {
|
||||
matches!(t.kind, token::Lt | token::OpenBrace | token::OpenParen)
|
||||
|
|
|
|||
|
|
@ -212,12 +212,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
&mut self,
|
||||
ident: Ident,
|
||||
ns: Namespace,
|
||||
new_binding: Decl<'ra>,
|
||||
old_binding: Decl<'ra>,
|
||||
new_binding: Decl<'ra>,
|
||||
) {
|
||||
// Error on the second of two conflicting names
|
||||
if old_binding.span.lo() > new_binding.span.lo() {
|
||||
return self.report_conflict(ident, ns, old_binding, new_binding);
|
||||
return self.report_conflict(ident, ns, new_binding, old_binding);
|
||||
}
|
||||
|
||||
let container = match old_binding.parent_module.unwrap().kind {
|
||||
|
|
|
|||
|
|
@ -300,13 +300,16 @@ fn remove_same_import<'ra>(d1: Decl<'ra>, d2: Decl<'ra>) -> (Decl<'ra>, Decl<'ra
|
|||
if let DeclKind::Import { import: import1, source_decl: d1_next } = d1.kind
|
||||
&& let DeclKind::Import { import: import2, source_decl: d2_next } = d2.kind
|
||||
&& import1 == import2
|
||||
&& d1.warn_ambiguity.get() == d2.warn_ambiguity.get()
|
||||
{
|
||||
assert_eq!(d1.ambiguity.get(), d2.ambiguity.get());
|
||||
assert!(!d1.warn_ambiguity.get());
|
||||
assert_eq!(d1.expansion, d2.expansion);
|
||||
assert_eq!(d1.span, d2.span);
|
||||
assert_eq!(d1.vis(), d2.vis());
|
||||
if d1.ambiguity.get() != d2.ambiguity.get() {
|
||||
assert!(d1.ambiguity.get().is_some());
|
||||
assert!(d2.ambiguity.get().is_none());
|
||||
}
|
||||
// Visibility of the new import declaration may be different,
|
||||
// because it already incorporates the visibility of the source binding.
|
||||
// `warn_ambiguity` of a re-fetched glob can also change in both directions.
|
||||
remove_same_import(d1_next, d2_next)
|
||||
} else {
|
||||
(d1, d2)
|
||||
|
|
@ -348,8 +351,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
/// decide which one to keep.
|
||||
fn select_glob_decl(
|
||||
&self,
|
||||
glob_decl: Decl<'ra>,
|
||||
old_glob_decl: Decl<'ra>,
|
||||
glob_decl: Decl<'ra>,
|
||||
warn_ambiguity: bool,
|
||||
) -> Decl<'ra> {
|
||||
assert!(glob_decl.is_glob_import());
|
||||
|
|
@ -369,7 +372,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
// with the re-fetched decls.
|
||||
// This is probably incorrect in corner cases, and the outdated decls still get
|
||||
// propagated to other places and get stuck there, but that's what we have at the moment.
|
||||
let (deep_decl, old_deep_decl) = remove_same_import(glob_decl, old_glob_decl);
|
||||
let (old_deep_decl, deep_decl) = remove_same_import(old_glob_decl, glob_decl);
|
||||
if deep_decl != glob_decl {
|
||||
// Some import layers have been removed, need to overwrite.
|
||||
assert_ne!(old_deep_decl, old_glob_decl);
|
||||
|
|
@ -377,6 +380,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
// assert_ne!(old_deep_decl, deep_decl);
|
||||
// assert!(old_deep_decl.is_glob_import());
|
||||
assert!(!deep_decl.is_glob_import());
|
||||
if old_glob_decl.ambiguity.get().is_some() && glob_decl.ambiguity.get().is_none() {
|
||||
// Do not lose glob ambiguities when re-fetching the glob.
|
||||
glob_decl.ambiguity.set_unchecked(old_glob_decl.ambiguity.get());
|
||||
}
|
||||
if glob_decl.is_ambiguity_recursive() {
|
||||
glob_decl.warn_ambiguity.set_unchecked(true);
|
||||
}
|
||||
|
|
@ -436,7 +443,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
match (old_decl.is_glob_import(), decl.is_glob_import()) {
|
||||
(true, true) => {
|
||||
resolution.glob_decl =
|
||||
Some(this.select_glob_decl(decl, old_decl, warn_ambiguity));
|
||||
Some(this.select_glob_decl(old_decl, decl, warn_ambiguity));
|
||||
}
|
||||
(old_glob @ true, false) | (old_glob @ false, true) => {
|
||||
let (glob_decl, non_glob_decl) =
|
||||
|
|
@ -446,7 +453,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
&& old_glob_decl != glob_decl
|
||||
{
|
||||
resolution.glob_decl =
|
||||
Some(this.select_glob_decl(glob_decl, old_glob_decl, false));
|
||||
Some(this.select_glob_decl(old_glob_decl, glob_decl, false));
|
||||
} else {
|
||||
resolution.glob_decl = Some(glob_decl);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1725,7 +1725,6 @@ symbols! {
|
|||
postfix_match,
|
||||
powerpc,
|
||||
powerpc64,
|
||||
powerpc64le,
|
||||
powerpc_target_feature,
|
||||
powf16,
|
||||
powf32,
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@ impl InlineAsmArch {
|
|||
Arch::Mips | Arch::Mips32r6 => Some(Self::Mips),
|
||||
Arch::Mips64 | Arch::Mips64r6 => Some(Self::Mips64),
|
||||
Arch::PowerPC => Some(Self::PowerPC),
|
||||
Arch::PowerPC64 | Arch::PowerPC64LE => Some(Self::PowerPC64),
|
||||
Arch::PowerPC64 => Some(Self::PowerPC64),
|
||||
Arch::S390x => Some(Self::S390x),
|
||||
Arch::Sparc => Some(Self::Sparc),
|
||||
Arch::Sparc64 => Some(Self::Sparc64),
|
||||
|
|
|
|||
|
|
@ -702,7 +702,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
|
|||
Arch::RiscV32 | Arch::RiscV64 => riscv::compute_abi_info(cx, self),
|
||||
Arch::Wasm32 | Arch::Wasm64 => wasm::compute_abi_info(cx, self),
|
||||
Arch::Bpf => bpf::compute_abi_info(cx, self),
|
||||
arch @ (Arch::PowerPC64LE | Arch::SpirV | Arch::Other(_)) => {
|
||||
arch @ (Arch::SpirV | Arch::Other(_)) => {
|
||||
panic!("no lowering implemented for {arch}")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1873,7 +1873,6 @@ crate::target_spec_enum! {
|
|||
Nvptx64 = "nvptx64",
|
||||
PowerPC = "powerpc",
|
||||
PowerPC64 = "powerpc64",
|
||||
PowerPC64LE = "powerpc64le",
|
||||
RiscV32 = "riscv32",
|
||||
RiscV64 = "riscv64",
|
||||
S390x = "s390x",
|
||||
|
|
@ -1911,7 +1910,6 @@ impl Arch {
|
|||
Self::Nvptx64 => sym::nvptx64,
|
||||
Self::PowerPC => sym::powerpc,
|
||||
Self::PowerPC64 => sym::powerpc64,
|
||||
Self::PowerPC64LE => sym::powerpc64le,
|
||||
Self::RiscV32 => sym::riscv32,
|
||||
Self::RiscV64 => sym::riscv64,
|
||||
Self::S390x => sym::s390x,
|
||||
|
|
@ -1940,8 +1938,8 @@ impl Arch {
|
|||
|
||||
AArch64 | AmdGpu | Arm | Arm64EC | Avr | CSky | Hexagon | LoongArch32 | LoongArch64
|
||||
| M68k | Mips | Mips32r6 | Mips64 | Mips64r6 | Msp430 | Nvptx64 | PowerPC
|
||||
| PowerPC64 | PowerPC64LE | RiscV32 | RiscV64 | S390x | Sparc | Sparc64 | Wasm32
|
||||
| Wasm64 | X86 | X86_64 | Xtensa => true,
|
||||
| PowerPC64 | RiscV32 | RiscV64 | S390x | Sparc | Sparc64 | Wasm32 | Wasm64 | X86
|
||||
| X86_64 | Xtensa => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3445,7 +3443,6 @@ impl Target {
|
|||
Arch::Arm64EC => (Architecture::Aarch64, Some(object::SubArchitecture::Arm64EC)),
|
||||
Arch::AmdGpu
|
||||
| Arch::Nvptx64
|
||||
| Arch::PowerPC64LE
|
||||
| Arch::SpirV
|
||||
| Arch::Wasm32
|
||||
| Arch::Wasm64
|
||||
|
|
|
|||
|
|
@ -986,7 +986,6 @@ impl Target {
|
|||
Arch::AmdGpu
|
||||
| Arch::Avr
|
||||
| Arch::Msp430
|
||||
| Arch::PowerPC64LE
|
||||
| Arch::SpirV
|
||||
| Arch::Xtensa
|
||||
| Arch::Other(_) => &[],
|
||||
|
|
@ -1015,12 +1014,7 @@ impl Target {
|
|||
Arch::CSky => CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
|
||||
// FIXME: for some tier3 targets, we are overly cautious and always give warnings
|
||||
// when passing args in vector registers.
|
||||
Arch::Avr
|
||||
| Arch::Msp430
|
||||
| Arch::PowerPC64LE
|
||||
| Arch::SpirV
|
||||
| Arch::Xtensa
|
||||
| Arch::Other(_) => &[],
|
||||
Arch::Avr | Arch::Msp430 | Arch::SpirV | Arch::Xtensa | Arch::Other(_) => &[],
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,15 @@ impl Thread {
|
|||
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
pub unsafe fn new(stack: usize, init: Box<ThreadInit>) -> io::Result<Thread> {
|
||||
// FIXME: remove this block once wasi-sdk is updated with the fix from
|
||||
// https://github.com/WebAssembly/wasi-libc/pull/716
|
||||
// WASI does not support threading via pthreads. While wasi-libc provides
|
||||
// pthread stubs, pthread_create returns EAGAIN, which causes confusing
|
||||
// errors. We return UNSUPPORTED_PLATFORM directly instead.
|
||||
if cfg!(target_os = "wasi") {
|
||||
return Err(io::Error::UNSUPPORTED_PLATFORM);
|
||||
}
|
||||
|
||||
let data = init;
|
||||
let mut attr: mem::MaybeUninit<libc::pthread_attr_t> = mem::MaybeUninit::uninit();
|
||||
assert_eq!(libc::pthread_attr_init(attr.as_mut_ptr()), 0);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ build = "build.rs"
|
|||
default-run = "bootstrap"
|
||||
|
||||
[features]
|
||||
build-metrics = ["sysinfo"]
|
||||
build-metrics = ["dep:sysinfo", "build_helper/metrics"]
|
||||
tracing = ["dep:tracing", "dep:tracing-chrome", "dep:tracing-subscriber", "dep:chrono", "dep:tempfile"]
|
||||
|
||||
[lib]
|
||||
|
|
|
|||
|
|
@ -6,5 +6,8 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
serde = "1"
|
||||
serde_derive = "1"
|
||||
serde = { version = "1", optional = true }
|
||||
serde_derive = { version = "1", optional = true }
|
||||
|
||||
[features]
|
||||
metrics = ["dep:serde", "dep:serde_derive"]
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ pub mod ci;
|
|||
pub mod drop_bomb;
|
||||
pub mod fs;
|
||||
pub mod git;
|
||||
#[cfg(feature = "metrics")]
|
||||
pub mod metrics;
|
||||
pub mod npm;
|
||||
pub mod stage0_parser;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ serde_yaml = "0.9"
|
|||
serde_json = "1"
|
||||
ureq = { version = "3", features = ["json"] }
|
||||
|
||||
build_helper = { path = "../../build_helper" }
|
||||
build_helper = { path = "../../build_helper", features = ["metrics"] }
|
||||
|
||||
[dev-dependencies]
|
||||
insta = "1"
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ use rustc_hir::attrs::{AttributeKind, DocAttribute, DocInline};
|
|||
use rustc_hir::def::{CtorKind, DefKind, MacroKinds, Res};
|
||||
use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE, LocalDefId};
|
||||
use rustc_hir::{LangItem, PredicateOrigin, find_attr};
|
||||
use rustc_hir_analysis::hir_ty_lowering::FeedConstTy;
|
||||
use rustc_hir_analysis::{lower_const_arg_for_rustdoc, lower_ty};
|
||||
use rustc_middle::metadata::Reexport;
|
||||
use rustc_middle::middle::resolve_bound_vars as rbv;
|
||||
|
|
@ -469,11 +468,17 @@ fn clean_middle_term<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
fn clean_hir_term<'tcx>(term: &hir::Term<'tcx>, cx: &mut DocContext<'tcx>) -> Term {
|
||||
fn clean_hir_term<'tcx>(
|
||||
assoc_item: Option<DefId>,
|
||||
term: &hir::Term<'tcx>,
|
||||
cx: &mut DocContext<'tcx>,
|
||||
) -> Term {
|
||||
match term {
|
||||
hir::Term::Ty(ty) => Term::Type(clean_ty(ty, cx)),
|
||||
hir::Term::Const(c) => {
|
||||
let ct = lower_const_arg_for_rustdoc(cx.tcx, c, FeedConstTy::No);
|
||||
// FIXME(generic_const_items): this should instantiate with the alias item's args
|
||||
let ty = cx.tcx.type_of(assoc_item.unwrap()).instantiate_identity();
|
||||
let ct = lower_const_arg_for_rustdoc(cx.tcx, c, ty);
|
||||
Term::Constant(clean_middle_const(ty::Binder::dummy(ct), cx))
|
||||
}
|
||||
}
|
||||
|
|
@ -650,7 +655,9 @@ fn clean_generic_param<'tcx>(
|
|||
GenericParamDefKind::Const {
|
||||
ty: Box::new(clean_ty(ty, cx)),
|
||||
default: default.map(|ct| {
|
||||
Box::new(lower_const_arg_for_rustdoc(cx.tcx, ct, FeedConstTy::No).to_string())
|
||||
Box::new(
|
||||
lower_const_arg_for_rustdoc(cx.tcx, ct, lower_ty(cx.tcx, ty)).to_string(),
|
||||
)
|
||||
}),
|
||||
},
|
||||
),
|
||||
|
|
@ -1531,7 +1538,7 @@ fn first_non_private_clean_path<'tcx>(
|
|||
&& path_last.args.is_some()
|
||||
{
|
||||
assert!(new_path_last.args.is_empty());
|
||||
new_path_last.args = clean_generic_args(path_last_args, cx);
|
||||
new_path_last.args = clean_generic_args(None, path_last_args, cx);
|
||||
}
|
||||
new_clean_path
|
||||
}
|
||||
|
|
@ -1812,7 +1819,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
|
|||
let length = match const_arg.kind {
|
||||
hir::ConstArgKind::Infer(..) | hir::ConstArgKind::Error(..) => "_".to_string(),
|
||||
hir::ConstArgKind::Anon(hir::AnonConst { def_id, .. }) => {
|
||||
let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, FeedConstTy::No);
|
||||
let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, cx.tcx.types.usize);
|
||||
let typing_env = ty::TypingEnv::post_analysis(cx.tcx, *def_id);
|
||||
let ct = cx.tcx.normalize_erasing_regions(typing_env, ct);
|
||||
print_const(cx, ct)
|
||||
|
|
@ -1823,7 +1830,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
|
|||
| hir::ConstArgKind::Tup(..)
|
||||
| hir::ConstArgKind::Array(..)
|
||||
| hir::ConstArgKind::Literal(..) => {
|
||||
let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, FeedConstTy::No);
|
||||
let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, cx.tcx.types.usize);
|
||||
print_const(cx, ct)
|
||||
}
|
||||
};
|
||||
|
|
@ -2516,6 +2523,7 @@ fn clean_path<'tcx>(path: &hir::Path<'tcx>, cx: &mut DocContext<'tcx>) -> Path {
|
|||
}
|
||||
|
||||
fn clean_generic_args<'tcx>(
|
||||
trait_did: Option<DefId>,
|
||||
generic_args: &hir::GenericArgs<'tcx>,
|
||||
cx: &mut DocContext<'tcx>,
|
||||
) -> GenericArgs {
|
||||
|
|
@ -2539,7 +2547,13 @@ fn clean_generic_args<'tcx>(
|
|||
let constraints = generic_args
|
||||
.constraints
|
||||
.iter()
|
||||
.map(|c| clean_assoc_item_constraint(c, cx))
|
||||
.map(|c| {
|
||||
clean_assoc_item_constraint(
|
||||
trait_did.expect("only trait ref has constraints"),
|
||||
c,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.collect::<ThinVec<_>>();
|
||||
GenericArgs::AngleBracketed { args, constraints }
|
||||
}
|
||||
|
|
@ -2562,7 +2576,11 @@ fn clean_path_segment<'tcx>(
|
|||
path: &hir::PathSegment<'tcx>,
|
||||
cx: &mut DocContext<'tcx>,
|
||||
) -> PathSegment {
|
||||
PathSegment { name: path.ident.name, args: clean_generic_args(path.args(), cx) }
|
||||
let trait_did = match path.res {
|
||||
hir::def::Res::Def(DefKind::Trait | DefKind::TraitAlias, did) => Some(did),
|
||||
_ => None,
|
||||
};
|
||||
PathSegment { name: path.ident.name, args: clean_generic_args(trait_did, path.args(), cx) }
|
||||
}
|
||||
|
||||
fn clean_bare_fn_ty<'tcx>(
|
||||
|
|
@ -3126,17 +3144,27 @@ fn clean_maybe_renamed_foreign_item<'tcx>(
|
|||
}
|
||||
|
||||
fn clean_assoc_item_constraint<'tcx>(
|
||||
trait_did: DefId,
|
||||
constraint: &hir::AssocItemConstraint<'tcx>,
|
||||
cx: &mut DocContext<'tcx>,
|
||||
) -> AssocItemConstraint {
|
||||
AssocItemConstraint {
|
||||
assoc: PathSegment {
|
||||
name: constraint.ident.name,
|
||||
args: clean_generic_args(constraint.gen_args, cx),
|
||||
args: clean_generic_args(None, constraint.gen_args, cx),
|
||||
},
|
||||
kind: match constraint.kind {
|
||||
hir::AssocItemConstraintKind::Equality { ref term } => {
|
||||
AssocItemConstraintKind::Equality { term: clean_hir_term(term, cx) }
|
||||
let assoc_tag = match term {
|
||||
hir::Term::Ty(_) => ty::AssocTag::Type,
|
||||
hir::Term::Const(_) => ty::AssocTag::Const,
|
||||
};
|
||||
let assoc_item = cx
|
||||
.tcx
|
||||
.associated_items(trait_did)
|
||||
.find_by_ident_and_kind(cx.tcx, constraint.ident, assoc_tag, trait_did)
|
||||
.map(|item| item.def_id);
|
||||
AssocItemConstraintKind::Equality { term: clean_hir_term(assoc_item, term, cx) }
|
||||
}
|
||||
hir::AssocItemConstraintKind::Bound { bounds } => AssocItemConstraintKind::Bound {
|
||||
bounds: bounds.iter().filter_map(|b| clean_generic_bound(b, cx)).collect(),
|
||||
|
|
|
|||
|
|
@ -309,24 +309,27 @@ impl<'tcx> LinkCollector<'_, 'tcx> {
|
|||
let ty_res = self.resolve_path(path, TypeNS, item_id, module_id).ok_or_else(no_res)?;
|
||||
|
||||
match ty_res {
|
||||
Res::Def(DefKind::Enum, did) => match tcx.type_of(did).instantiate_identity().kind() {
|
||||
ty::Adt(def, _) if def.is_enum() => {
|
||||
if let Some(variant) = def.variants().iter().find(|v| v.name == variant_name)
|
||||
&& let Some(field) =
|
||||
variant.fields.iter().find(|f| f.name == variant_field_name)
|
||||
{
|
||||
Ok((ty_res, field.did))
|
||||
} else {
|
||||
Err(UnresolvedPath {
|
||||
item_id,
|
||||
module_id,
|
||||
partial_res: Some(Res::Def(DefKind::Enum, def.did())),
|
||||
unresolved: variant_field_name.to_string().into(),
|
||||
})
|
||||
Res::Def(DefKind::Enum | DefKind::TyAlias, did) => {
|
||||
match tcx.type_of(did).instantiate_identity().kind() {
|
||||
ty::Adt(def, _) if def.is_enum() => {
|
||||
if let Some(variant) =
|
||||
def.variants().iter().find(|v| v.name == variant_name)
|
||||
&& let Some(field) =
|
||||
variant.fields.iter().find(|f| f.name == variant_field_name)
|
||||
{
|
||||
Ok((ty_res, field.did))
|
||||
} else {
|
||||
Err(UnresolvedPath {
|
||||
item_id,
|
||||
module_id,
|
||||
partial_res: Some(Res::Def(DefKind::Enum, def.did())),
|
||||
unresolved: variant_field_name.to_string().into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
}
|
||||
_ => Err(UnresolvedPath {
|
||||
item_id,
|
||||
module_id,
|
||||
|
|
@ -336,58 +339,6 @@ impl<'tcx> LinkCollector<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Given a primitive type, try to resolve an associated item.
|
||||
fn resolve_primitive_associated_item(
|
||||
&self,
|
||||
prim_ty: PrimitiveType,
|
||||
ns: Namespace,
|
||||
item_name: Symbol,
|
||||
) -> Vec<(Res, DefId)> {
|
||||
let tcx = self.cx.tcx;
|
||||
|
||||
prim_ty
|
||||
.impls(tcx)
|
||||
.flat_map(|impl_| {
|
||||
filter_assoc_items_by_name_and_namespace(
|
||||
tcx,
|
||||
impl_,
|
||||
Ident::with_dummy_span(item_name),
|
||||
ns,
|
||||
)
|
||||
.map(|item| (Res::Primitive(prim_ty), item.def_id))
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn resolve_self_ty(&self, path_str: &str, ns: Namespace, item_id: DefId) -> Option<Res> {
|
||||
if ns != TypeNS || path_str != "Self" {
|
||||
return None;
|
||||
}
|
||||
|
||||
let tcx = self.cx.tcx;
|
||||
let self_id = match tcx.def_kind(item_id) {
|
||||
def_kind @ (DefKind::AssocFn
|
||||
| DefKind::AssocConst
|
||||
| DefKind::AssocTy
|
||||
| DefKind::Variant
|
||||
| DefKind::Field) => {
|
||||
let parent_def_id = tcx.parent(item_id);
|
||||
if def_kind == DefKind::Field && tcx.def_kind(parent_def_id) == DefKind::Variant {
|
||||
tcx.parent(parent_def_id)
|
||||
} else {
|
||||
parent_def_id
|
||||
}
|
||||
}
|
||||
_ => item_id,
|
||||
};
|
||||
|
||||
match tcx.def_kind(self_id) {
|
||||
DefKind::Impl { .. } => self.def_id_to_res(self_id),
|
||||
DefKind::Use => None,
|
||||
def_kind => Some(Res::Def(def_kind, self_id)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience wrapper around `doc_link_resolutions`.
|
||||
///
|
||||
/// This also handles resolving `true` and `false` as booleans.
|
||||
|
|
@ -400,7 +351,7 @@ impl<'tcx> LinkCollector<'_, 'tcx> {
|
|||
item_id: DefId,
|
||||
module_id: DefId,
|
||||
) -> Option<Res> {
|
||||
if let res @ Some(..) = self.resolve_self_ty(path_str, ns, item_id) {
|
||||
if let res @ Some(..) = resolve_self_ty(self.cx.tcx, path_str, ns, item_id) {
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -430,13 +381,15 @@ impl<'tcx> LinkCollector<'_, 'tcx> {
|
|||
/// Resolves a string as a path within a particular namespace. Returns an
|
||||
/// optional URL fragment in the case of variants and methods.
|
||||
fn resolve<'path>(
|
||||
&mut self,
|
||||
&self,
|
||||
path_str: &'path str,
|
||||
ns: Namespace,
|
||||
disambiguator: Option<Disambiguator>,
|
||||
item_id: DefId,
|
||||
module_id: DefId,
|
||||
) -> Result<Vec<(Res, Option<DefId>)>, UnresolvedPath<'path>> {
|
||||
let tcx = self.cx.tcx;
|
||||
|
||||
if let Some(res) = self.resolve_path(path_str, ns, item_id, module_id) {
|
||||
return Ok(match res {
|
||||
Res::Def(
|
||||
|
|
@ -482,7 +435,7 @@ impl<'tcx> LinkCollector<'_, 'tcx> {
|
|||
match resolve_primitive(path_root, TypeNS)
|
||||
.or_else(|| self.resolve_path(path_root, TypeNS, item_id, module_id))
|
||||
.map(|ty_res| {
|
||||
self.resolve_associated_item(ty_res, item_name, ns, disambiguator, module_id)
|
||||
resolve_associated_item(tcx, ty_res, item_name, ns, disambiguator, module_id)
|
||||
.into_iter()
|
||||
.map(|(res, def_id)| (res, Some(def_id)))
|
||||
.collect::<Vec<_>>()
|
||||
|
|
@ -503,246 +456,323 @@ impl<'tcx> LinkCollector<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a DefId to a Res, where possible.
|
||||
///
|
||||
/// This is used for resolving type aliases.
|
||||
fn def_id_to_res(&self, ty_id: DefId) -> Option<Res> {
|
||||
use PrimitiveType::*;
|
||||
Some(match *self.cx.tcx.type_of(ty_id).instantiate_identity().kind() {
|
||||
ty::Bool => Res::Primitive(Bool),
|
||||
ty::Char => Res::Primitive(Char),
|
||||
ty::Int(ity) => Res::Primitive(ity.into()),
|
||||
ty::Uint(uty) => Res::Primitive(uty.into()),
|
||||
ty::Float(fty) => Res::Primitive(fty.into()),
|
||||
ty::Str => Res::Primitive(Str),
|
||||
ty::Tuple(tys) if tys.is_empty() => Res::Primitive(Unit),
|
||||
ty::Tuple(_) => Res::Primitive(Tuple),
|
||||
ty::Pat(..) => Res::Primitive(Pat),
|
||||
ty::Array(..) => Res::Primitive(Array),
|
||||
ty::Slice(_) => Res::Primitive(Slice),
|
||||
ty::RawPtr(_, _) => Res::Primitive(RawPointer),
|
||||
ty::Ref(..) => Res::Primitive(Reference),
|
||||
ty::FnDef(..) => panic!("type alias to a function definition"),
|
||||
ty::FnPtr(..) => Res::Primitive(Fn),
|
||||
ty::Never => Res::Primitive(Never),
|
||||
ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did, .. }, _)), _) | ty::Foreign(did) => {
|
||||
Res::from_def_id(self.cx.tcx, did)
|
||||
}
|
||||
ty::Alias(..)
|
||||
| ty::Closure(..)
|
||||
| ty::CoroutineClosure(..)
|
||||
| ty::Coroutine(..)
|
||||
| ty::CoroutineWitness(..)
|
||||
| ty::Dynamic(..)
|
||||
| ty::UnsafeBinder(_)
|
||||
| ty::Param(_)
|
||||
| ty::Bound(..)
|
||||
| ty::Placeholder(_)
|
||||
| ty::Infer(_)
|
||||
| ty::Error(_) => return None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Convert a PrimitiveType to a Ty, where possible.
|
||||
///
|
||||
/// This is used for resolving trait impls for primitives
|
||||
fn primitive_type_to_ty(&mut self, prim: PrimitiveType) -> Option<Ty<'tcx>> {
|
||||
use PrimitiveType::*;
|
||||
let tcx = self.cx.tcx;
|
||||
|
||||
// FIXME: Only simple types are supported here, see if we can support
|
||||
// other types such as Tuple, Array, Slice, etc.
|
||||
// See https://github.com/rust-lang/rust/issues/90703#issuecomment-1004263455
|
||||
Some(match prim {
|
||||
Bool => tcx.types.bool,
|
||||
Str => tcx.types.str_,
|
||||
Char => tcx.types.char,
|
||||
Never => tcx.types.never,
|
||||
I8 => tcx.types.i8,
|
||||
I16 => tcx.types.i16,
|
||||
I32 => tcx.types.i32,
|
||||
I64 => tcx.types.i64,
|
||||
I128 => tcx.types.i128,
|
||||
Isize => tcx.types.isize,
|
||||
F16 => tcx.types.f16,
|
||||
F32 => tcx.types.f32,
|
||||
F64 => tcx.types.f64,
|
||||
F128 => tcx.types.f128,
|
||||
U8 => tcx.types.u8,
|
||||
U16 => tcx.types.u16,
|
||||
U32 => tcx.types.u32,
|
||||
U64 => tcx.types.u64,
|
||||
U128 => tcx.types.u128,
|
||||
Usize => tcx.types.usize,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Resolve an associated item, returning its containing page's `Res`
|
||||
/// and the fragment targeting the associated item on its page.
|
||||
fn resolve_associated_item(
|
||||
&mut self,
|
||||
root_res: Res,
|
||||
item_name: Symbol,
|
||||
ns: Namespace,
|
||||
disambiguator: Option<Disambiguator>,
|
||||
module_id: DefId,
|
||||
) -> Vec<(Res, DefId)> {
|
||||
let tcx = self.cx.tcx;
|
||||
|
||||
match root_res {
|
||||
Res::Primitive(prim) => {
|
||||
let items = self.resolve_primitive_associated_item(prim, ns, item_name);
|
||||
if !items.is_empty() {
|
||||
items
|
||||
// Inherent associated items take precedence over items that come from trait impls.
|
||||
} else {
|
||||
self.primitive_type_to_ty(prim)
|
||||
.map(|ty| {
|
||||
resolve_associated_trait_item(ty, module_id, item_name, ns, self.cx)
|
||||
.iter()
|
||||
.map(|item| (root_res, item.def_id))
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
Res::Def(DefKind::TyAlias, did) => {
|
||||
// Resolve the link on the type the alias points to.
|
||||
// FIXME: if the associated item is defined directly on the type alias,
|
||||
// it will show up on its documentation page, we should link there instead.
|
||||
let Some(res) = self.def_id_to_res(did) else { return Vec::new() };
|
||||
self.resolve_associated_item(res, item_name, ns, disambiguator, module_id)
|
||||
}
|
||||
Res::Def(
|
||||
def_kind @ (DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::ForeignTy),
|
||||
did,
|
||||
) => {
|
||||
debug!("looking for associated item named {item_name} for item {did:?}");
|
||||
// Checks if item_name is a variant of the `SomeItem` enum
|
||||
if ns == TypeNS && def_kind == DefKind::Enum {
|
||||
match tcx.type_of(did).instantiate_identity().kind() {
|
||||
ty::Adt(adt_def, _) => {
|
||||
for variant in adt_def.variants() {
|
||||
if variant.name == item_name {
|
||||
return vec![(root_res, variant.def_id)];
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
let search_for_field = || {
|
||||
let (DefKind::Struct | DefKind::Union) = def_kind else { return vec![] };
|
||||
debug!("looking for fields named {item_name} for {did:?}");
|
||||
// FIXME: this doesn't really belong in `associated_item` (maybe `variant_field` is better?)
|
||||
// NOTE: it's different from variant_field because it only resolves struct fields,
|
||||
// not variant fields (2 path segments, not 3).
|
||||
//
|
||||
// We need to handle struct (and union) fields in this code because
|
||||
// syntactically their paths are identical to associated item paths:
|
||||
// `module::Type::field` and `module::Type::Assoc`.
|
||||
//
|
||||
// On the other hand, variant fields can't be mistaken for associated
|
||||
// items because they look like this: `module::Type::Variant::field`.
|
||||
//
|
||||
// Variants themselves don't need to be handled here, even though
|
||||
// they also look like associated items (`module::Type::Variant`),
|
||||
// because they are real Rust syntax (unlike the intra-doc links
|
||||
// field syntax) and are handled by the compiler's resolver.
|
||||
let ty::Adt(def, _) = tcx.type_of(did).instantiate_identity().kind() else {
|
||||
unreachable!()
|
||||
};
|
||||
def.non_enum_variant()
|
||||
.fields
|
||||
.iter()
|
||||
.filter(|field| field.name == item_name)
|
||||
.map(|field| (root_res, field.did))
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
|
||||
if let Some(Disambiguator::Kind(DefKind::Field)) = disambiguator {
|
||||
return search_for_field();
|
||||
}
|
||||
|
||||
// Checks if item_name belongs to `impl SomeItem`
|
||||
let mut assoc_items: Vec<_> = tcx
|
||||
.inherent_impls(did)
|
||||
.iter()
|
||||
.flat_map(|&imp| {
|
||||
filter_assoc_items_by_name_and_namespace(
|
||||
tcx,
|
||||
imp,
|
||||
Ident::with_dummy_span(item_name),
|
||||
ns,
|
||||
)
|
||||
})
|
||||
.map(|item| (root_res, item.def_id))
|
||||
.collect();
|
||||
|
||||
if assoc_items.is_empty() {
|
||||
// Check if item_name belongs to `impl SomeTrait for SomeItem`
|
||||
// FIXME(#74563): This gives precedence to `impl SomeItem`:
|
||||
// Although having both would be ambiguous, use impl version for compatibility's sake.
|
||||
// To handle that properly resolve() would have to support
|
||||
// something like [`ambi_fn`](<SomeStruct as SomeTrait>::ambi_fn)
|
||||
assoc_items = resolve_associated_trait_item(
|
||||
tcx.type_of(did).instantiate_identity(),
|
||||
module_id,
|
||||
item_name,
|
||||
ns,
|
||||
self.cx,
|
||||
)
|
||||
.into_iter()
|
||||
.map(|item| (root_res, item.def_id))
|
||||
.collect::<Vec<_>>();
|
||||
}
|
||||
|
||||
debug!("got associated item {assoc_items:?}");
|
||||
|
||||
if !assoc_items.is_empty() {
|
||||
return assoc_items;
|
||||
}
|
||||
|
||||
if ns != Namespace::ValueNS {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
search_for_field()
|
||||
}
|
||||
Res::Def(DefKind::Trait, did) => filter_assoc_items_by_name_and_namespace(
|
||||
tcx,
|
||||
did,
|
||||
Ident::with_dummy_span(item_name),
|
||||
ns,
|
||||
)
|
||||
.map(|item| {
|
||||
let res = Res::Def(item.as_def_kind(), item.def_id);
|
||||
(res, item.def_id)
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
_ => Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn full_res(tcx: TyCtxt<'_>, (base, assoc_item): (Res, Option<DefId>)) -> Res {
|
||||
assoc_item.map_or(base, |def_id| Res::from_def_id(tcx, def_id))
|
||||
}
|
||||
|
||||
/// Given a primitive type, try to resolve an associated item.
|
||||
fn resolve_primitive_inherent_assoc_item<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
prim_ty: PrimitiveType,
|
||||
ns: Namespace,
|
||||
item_ident: Ident,
|
||||
) -> Vec<(Res, DefId)> {
|
||||
prim_ty
|
||||
.impls(tcx)
|
||||
.flat_map(|impl_| {
|
||||
filter_assoc_items_by_name_and_namespace(tcx, impl_, item_ident, ns)
|
||||
.map(|item| (Res::Primitive(prim_ty), item.def_id))
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn resolve_self_ty<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
path_str: &str,
|
||||
ns: Namespace,
|
||||
item_id: DefId,
|
||||
) -> Option<Res> {
|
||||
if ns != TypeNS || path_str != "Self" {
|
||||
return None;
|
||||
}
|
||||
|
||||
let self_id = match tcx.def_kind(item_id) {
|
||||
def_kind @ (DefKind::AssocFn
|
||||
| DefKind::AssocConst
|
||||
| DefKind::AssocTy
|
||||
| DefKind::Variant
|
||||
| DefKind::Field) => {
|
||||
let parent_def_id = tcx.parent(item_id);
|
||||
if def_kind == DefKind::Field && tcx.def_kind(parent_def_id) == DefKind::Variant {
|
||||
tcx.parent(parent_def_id)
|
||||
} else {
|
||||
parent_def_id
|
||||
}
|
||||
}
|
||||
_ => item_id,
|
||||
};
|
||||
|
||||
match tcx.def_kind(self_id) {
|
||||
DefKind::Impl { .. } => ty_to_res(tcx, tcx.type_of(self_id).instantiate_identity()),
|
||||
DefKind::Use => None,
|
||||
def_kind => Some(Res::Def(def_kind, self_id)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a Ty to a Res, where possible.
|
||||
///
|
||||
/// This is used for resolving type aliases.
|
||||
fn ty_to_res<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Res> {
|
||||
use PrimitiveType::*;
|
||||
Some(match *ty.kind() {
|
||||
ty::Bool => Res::Primitive(Bool),
|
||||
ty::Char => Res::Primitive(Char),
|
||||
ty::Int(ity) => Res::Primitive(ity.into()),
|
||||
ty::Uint(uty) => Res::Primitive(uty.into()),
|
||||
ty::Float(fty) => Res::Primitive(fty.into()),
|
||||
ty::Str => Res::Primitive(Str),
|
||||
ty::Tuple(tys) if tys.is_empty() => Res::Primitive(Unit),
|
||||
ty::Tuple(_) => Res::Primitive(Tuple),
|
||||
ty::Pat(..) => Res::Primitive(Pat),
|
||||
ty::Array(..) => Res::Primitive(Array),
|
||||
ty::Slice(_) => Res::Primitive(Slice),
|
||||
ty::RawPtr(_, _) => Res::Primitive(RawPointer),
|
||||
ty::Ref(..) => Res::Primitive(Reference),
|
||||
ty::FnDef(..) => panic!("type alias to a function definition"),
|
||||
ty::FnPtr(..) => Res::Primitive(Fn),
|
||||
ty::Never => Res::Primitive(Never),
|
||||
ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did, .. }, _)), _) | ty::Foreign(did) => {
|
||||
Res::from_def_id(tcx, did)
|
||||
}
|
||||
ty::Alias(..)
|
||||
| ty::Closure(..)
|
||||
| ty::CoroutineClosure(..)
|
||||
| ty::Coroutine(..)
|
||||
| ty::CoroutineWitness(..)
|
||||
| ty::Dynamic(..)
|
||||
| ty::UnsafeBinder(_)
|
||||
| ty::Param(_)
|
||||
| ty::Bound(..)
|
||||
| ty::Placeholder(_)
|
||||
| ty::Infer(_)
|
||||
| ty::Error(_) => return None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Convert a PrimitiveType to a Ty, where possible.
|
||||
///
|
||||
/// This is used for resolving trait impls for primitives
|
||||
fn primitive_type_to_ty<'tcx>(tcx: TyCtxt<'tcx>, prim: PrimitiveType) -> Option<Ty<'tcx>> {
|
||||
use PrimitiveType::*;
|
||||
|
||||
// FIXME: Only simple types are supported here, see if we can support
|
||||
// other types such as Tuple, Array, Slice, etc.
|
||||
// See https://github.com/rust-lang/rust/issues/90703#issuecomment-1004263455
|
||||
Some(match prim {
|
||||
Bool => tcx.types.bool,
|
||||
Str => tcx.types.str_,
|
||||
Char => tcx.types.char,
|
||||
Never => tcx.types.never,
|
||||
I8 => tcx.types.i8,
|
||||
I16 => tcx.types.i16,
|
||||
I32 => tcx.types.i32,
|
||||
I64 => tcx.types.i64,
|
||||
I128 => tcx.types.i128,
|
||||
Isize => tcx.types.isize,
|
||||
F16 => tcx.types.f16,
|
||||
F32 => tcx.types.f32,
|
||||
F64 => tcx.types.f64,
|
||||
F128 => tcx.types.f128,
|
||||
U8 => tcx.types.u8,
|
||||
U16 => tcx.types.u16,
|
||||
U32 => tcx.types.u32,
|
||||
U64 => tcx.types.u64,
|
||||
U128 => tcx.types.u128,
|
||||
Usize => tcx.types.usize,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Resolve an associated item, returning its containing page's `Res`
|
||||
/// and the fragment targeting the associated item on its page.
|
||||
fn resolve_associated_item<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
root_res: Res,
|
||||
item_name: Symbol,
|
||||
ns: Namespace,
|
||||
disambiguator: Option<Disambiguator>,
|
||||
module_id: DefId,
|
||||
) -> Vec<(Res, DefId)> {
|
||||
let item_ident = Ident::with_dummy_span(item_name);
|
||||
|
||||
match root_res {
|
||||
Res::Def(DefKind::TyAlias, alias_did) => {
|
||||
// Resolve the link on the type the alias points to.
|
||||
// FIXME: if the associated item is defined directly on the type alias,
|
||||
// it will show up on its documentation page, we should link there instead.
|
||||
let Some(aliased_res) = ty_to_res(tcx, tcx.type_of(alias_did).instantiate_identity())
|
||||
else {
|
||||
return vec![];
|
||||
};
|
||||
let aliased_items =
|
||||
resolve_associated_item(tcx, aliased_res, item_name, ns, disambiguator, module_id);
|
||||
aliased_items
|
||||
.into_iter()
|
||||
.map(|(res, assoc_did)| {
|
||||
if is_assoc_item_on_alias_page(tcx, assoc_did) {
|
||||
(root_res, assoc_did)
|
||||
} else {
|
||||
(res, assoc_did)
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
Res::Primitive(prim) => resolve_assoc_on_primitive(tcx, prim, ns, item_ident, module_id),
|
||||
Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum, did) => {
|
||||
resolve_assoc_on_adt(tcx, did, item_ident, ns, disambiguator, module_id)
|
||||
}
|
||||
Res::Def(DefKind::ForeignTy, did) => {
|
||||
resolve_assoc_on_simple_type(tcx, did, item_ident, ns, module_id)
|
||||
}
|
||||
Res::Def(DefKind::Trait, did) => filter_assoc_items_by_name_and_namespace(
|
||||
tcx,
|
||||
did,
|
||||
Ident::with_dummy_span(item_name),
|
||||
ns,
|
||||
)
|
||||
.map(|item| (root_res, item.def_id))
|
||||
.collect::<Vec<_>>(),
|
||||
_ => Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: make this fully complete by also including ALL inherent impls
|
||||
// and trait impls BUT ONLY if on alias directly
|
||||
fn is_assoc_item_on_alias_page<'tcx>(tcx: TyCtxt<'tcx>, assoc_did: DefId) -> bool {
|
||||
match tcx.def_kind(assoc_did) {
|
||||
// Variants and fields always have docs on the alias page.
|
||||
DefKind::Variant | DefKind::Field => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_assoc_on_primitive<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
prim: PrimitiveType,
|
||||
ns: Namespace,
|
||||
item_ident: Ident,
|
||||
module_id: DefId,
|
||||
) -> Vec<(Res, DefId)> {
|
||||
let root_res = Res::Primitive(prim);
|
||||
let items = resolve_primitive_inherent_assoc_item(tcx, prim, ns, item_ident);
|
||||
if !items.is_empty() {
|
||||
items
|
||||
// Inherent associated items take precedence over items that come from trait impls.
|
||||
} else {
|
||||
primitive_type_to_ty(tcx, prim)
|
||||
.map(|ty| {
|
||||
resolve_associated_trait_item(ty, module_id, item_ident, ns, tcx)
|
||||
.iter()
|
||||
.map(|item| (root_res, item.def_id))
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_assoc_on_adt<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
adt_def_id: DefId,
|
||||
item_ident: Ident,
|
||||
ns: Namespace,
|
||||
disambiguator: Option<Disambiguator>,
|
||||
module_id: DefId,
|
||||
) -> Vec<(Res, DefId)> {
|
||||
debug!("looking for associated item named {item_ident} for item {adt_def_id:?}");
|
||||
let root_res = Res::from_def_id(tcx, adt_def_id);
|
||||
let adt_ty = tcx.type_of(adt_def_id).instantiate_identity();
|
||||
let adt_def = adt_ty.ty_adt_def().expect("must be ADT");
|
||||
// Checks if item_name is a variant of the `SomeItem` enum
|
||||
if ns == TypeNS && adt_def.is_enum() {
|
||||
for variant in adt_def.variants() {
|
||||
if variant.name == item_ident.name {
|
||||
return vec![(root_res, variant.def_id)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(Disambiguator::Kind(DefKind::Field)) = disambiguator
|
||||
&& (adt_def.is_struct() || adt_def.is_union())
|
||||
{
|
||||
return resolve_structfield(adt_def, item_ident.name)
|
||||
.into_iter()
|
||||
.map(|did| (root_res, did))
|
||||
.collect();
|
||||
}
|
||||
|
||||
let assoc_items = resolve_assoc_on_simple_type(tcx, adt_def_id, item_ident, ns, module_id);
|
||||
if !assoc_items.is_empty() {
|
||||
return assoc_items;
|
||||
}
|
||||
|
||||
if ns == Namespace::ValueNS && (adt_def.is_struct() || adt_def.is_union()) {
|
||||
return resolve_structfield(adt_def, item_ident.name)
|
||||
.into_iter()
|
||||
.map(|did| (root_res, did))
|
||||
.collect();
|
||||
}
|
||||
|
||||
vec![]
|
||||
}
|
||||
|
||||
/// "Simple" i.e. an ADT, foreign type, etc. -- not a type alias, primitive type, or other trickier type.
|
||||
fn resolve_assoc_on_simple_type<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ty_def_id: DefId,
|
||||
item_ident: Ident,
|
||||
ns: Namespace,
|
||||
module_id: DefId,
|
||||
) -> Vec<(Res, DefId)> {
|
||||
let root_res = Res::from_def_id(tcx, ty_def_id);
|
||||
// Checks if item_name belongs to `impl SomeItem`
|
||||
let inherent_assoc_items: Vec<_> = tcx
|
||||
.inherent_impls(ty_def_id)
|
||||
.iter()
|
||||
.flat_map(|&imp| filter_assoc_items_by_name_and_namespace(tcx, imp, item_ident, ns))
|
||||
.map(|item| (root_res, item.def_id))
|
||||
.collect();
|
||||
debug!("got inherent assoc items {inherent_assoc_items:?}");
|
||||
if !inherent_assoc_items.is_empty() {
|
||||
return inherent_assoc_items;
|
||||
}
|
||||
|
||||
// Check if item_name belongs to `impl SomeTrait for SomeItem`
|
||||
// FIXME(#74563): This gives precedence to `impl SomeItem`:
|
||||
// Although having both would be ambiguous, use impl version for compatibility's sake.
|
||||
// To handle that properly resolve() would have to support
|
||||
// something like [`ambi_fn`](<SomeStruct as SomeTrait>::ambi_fn)
|
||||
let ty = tcx.type_of(ty_def_id).instantiate_identity();
|
||||
let trait_assoc_items = resolve_associated_trait_item(ty, module_id, item_ident, ns, tcx)
|
||||
.into_iter()
|
||||
.map(|item| (root_res, item.def_id))
|
||||
.collect::<Vec<_>>();
|
||||
debug!("got trait assoc items {trait_assoc_items:?}");
|
||||
trait_assoc_items
|
||||
}
|
||||
|
||||
fn resolve_structfield<'tcx>(adt_def: ty::AdtDef<'tcx>, item_name: Symbol) -> Option<DefId> {
|
||||
debug!("looking for fields named {item_name} for {adt_def:?}");
|
||||
adt_def
|
||||
.non_enum_variant()
|
||||
.fields
|
||||
.iter()
|
||||
.find(|field| field.name == item_name)
|
||||
.map(|field| field.did)
|
||||
}
|
||||
|
||||
/// Look to see if a resolved item has an associated item named `item_name`.
|
||||
///
|
||||
/// Given `[std::io::Error::source]`, where `source` is unresolved, this would
|
||||
/// find `std::error::Error::source` and return
|
||||
/// `<io::Error as error::Error>::source`.
|
||||
fn resolve_associated_trait_item<'a>(
|
||||
ty: Ty<'a>,
|
||||
fn resolve_associated_trait_item<'tcx>(
|
||||
ty: Ty<'tcx>,
|
||||
module: DefId,
|
||||
item_name: Symbol,
|
||||
item_ident: Ident,
|
||||
ns: Namespace,
|
||||
cx: &mut DocContext<'a>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> Vec<ty::AssocItem> {
|
||||
// FIXME: this should also consider blanket impls (`impl<T> X for T`). Unfortunately
|
||||
// `get_auto_trait_and_blanket_impls` is broken because the caching behavior is wrong. In the
|
||||
|
|
@ -750,22 +780,17 @@ fn resolve_associated_trait_item<'a>(
|
|||
|
||||
// Next consider explicit impls: `impl MyTrait for MyType`
|
||||
// Give precedence to inherent impls.
|
||||
let traits = trait_impls_for(cx, ty, module);
|
||||
let tcx = cx.tcx;
|
||||
let traits = trait_impls_for(tcx, ty, module);
|
||||
debug!("considering traits {traits:?}");
|
||||
let candidates = traits
|
||||
.iter()
|
||||
.flat_map(|&(impl_, trait_)| {
|
||||
filter_assoc_items_by_name_and_namespace(
|
||||
tcx,
|
||||
trait_,
|
||||
Ident::with_dummy_span(item_name),
|
||||
ns,
|
||||
filter_assoc_items_by_name_and_namespace(tcx, trait_, item_ident, ns).map(
|
||||
move |trait_assoc| {
|
||||
trait_assoc_to_impl_assoc_item(tcx, impl_, trait_assoc.def_id)
|
||||
.unwrap_or(*trait_assoc)
|
||||
},
|
||||
)
|
||||
.map(move |trait_assoc| {
|
||||
trait_assoc_to_impl_assoc_item(tcx, impl_, trait_assoc.def_id)
|
||||
.unwrap_or(*trait_assoc)
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
// FIXME(#74563): warn about ambiguity
|
||||
|
|
@ -800,13 +825,12 @@ fn trait_assoc_to_impl_assoc_item<'tcx>(
|
|||
///
|
||||
/// NOTE: this cannot be a query because more traits could be available when more crates are compiled!
|
||||
/// So it is not stable to serialize cross-crate.
|
||||
#[instrument(level = "debug", skip(cx))]
|
||||
fn trait_impls_for<'a>(
|
||||
cx: &mut DocContext<'a>,
|
||||
ty: Ty<'a>,
|
||||
#[instrument(level = "debug", skip(tcx))]
|
||||
fn trait_impls_for<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
module: DefId,
|
||||
) -> FxIndexSet<(DefId, DefId)> {
|
||||
let tcx = cx.tcx;
|
||||
let mut impls = FxIndexSet::default();
|
||||
|
||||
for &trait_ in tcx.doc_link_traits_in_scope(module) {
|
||||
|
|
@ -1540,7 +1564,7 @@ impl LinkCollector<'_, '_> {
|
|||
}
|
||||
None => {
|
||||
// Try everything!
|
||||
let mut candidate = |ns| {
|
||||
let candidate = |ns| {
|
||||
self.resolve(path_str, ns, None, item_id, module_id)
|
||||
.map_err(ResolutionFailure::NotResolved)
|
||||
};
|
||||
|
|
@ -1926,7 +1950,7 @@ fn report_diagnostic(
|
|||
/// handled earlier. For example, if passed `Item::Crate(std)` and `path_str`
|
||||
/// `std::io::Error::x`, this will resolve `std::io::Error`.
|
||||
fn resolution_failure(
|
||||
collector: &mut LinkCollector<'_, '_>,
|
||||
collector: &LinkCollector<'_, '_>,
|
||||
diag_info: DiagnosticInfo<'_>,
|
||||
path_str: &str,
|
||||
disambiguator: Option<Disambiguator>,
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
| Arch::Bpf
|
||||
| Arch::Msp430
|
||||
| Arch::Nvptx64
|
||||
| Arch::PowerPC64LE
|
||||
| Arch::SpirV
|
||||
| Arch::Other(_)) => bug!("unsupported target architecture for malloc: `{arch}`"),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ version = "0.1.0"
|
|||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
build_helper = { path = "../../build_helper" }
|
||||
build_helper = { path = "../../build_helper", features = ["metrics"] }
|
||||
env_logger = "0.11"
|
||||
log = "0.4"
|
||||
anyhow = "1"
|
||||
|
|
|
|||
71
tests/rustdoc-html/intra-doc/adt-through-alias.rs
Normal file
71
tests/rustdoc-html/intra-doc/adt-through-alias.rs
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
#![crate_name = "foo"]
|
||||
|
||||
//! [`TheStructAlias::the_field`]
|
||||
//! [`TheEnumAlias::TheVariant`]
|
||||
//! [`TheEnumAlias::TheVariant::the_field`]
|
||||
//! [`TheUnionAlias::f1`]
|
||||
//!
|
||||
//! [`TheStruct::trait_`]
|
||||
//! [`TheStructAlias::trait_`]
|
||||
//! [`TheEnum::trait_`]
|
||||
//! [`TheEnumAlias::trait_`]
|
||||
//!
|
||||
//! [`TheStruct::inherent`]
|
||||
//! [`TheStructAlias::inherent`]
|
||||
//! [`TheEnum::inherent`]
|
||||
//! [`TheEnumAlias::inherent`]
|
||||
|
||||
//@ has foo/index.html '//a[@href="type.TheStructAlias.html#structfield.the_field"]' 'TheStructAlias::the_field'
|
||||
//@ has foo/index.html '//a[@href="type.TheEnumAlias.html#variant.TheVariant"]' 'TheEnumAlias::TheVariant'
|
||||
//@ has foo/index.html '//a[@href="type.TheEnumAlias.html#variant.TheVariant.field.the_field"]' 'TheEnumAlias::TheVariant::the_field'
|
||||
//@ has foo/index.html '//a[@href="type.TheUnionAlias.html#structfield.f1"]' 'TheUnionAlias::f1'
|
||||
|
||||
//@ has foo/index.html '//a[@href="struct.TheStruct.html#method.trait_"]' 'TheStruct::trait_'
|
||||
//@ has foo/index.html '//a[@href="struct.TheStruct.html#method.trait_"]' 'TheStructAlias::trait_'
|
||||
//@ has foo/index.html '//a[@href="enum.TheEnum.html#method.trait_"]' 'TheEnum::trait_'
|
||||
// FIXME: this one should resolve to alias since it's impl Trait for TheEnumAlias
|
||||
//@ has foo/index.html '//a[@href="enum.TheEnum.html#method.trait_"]' 'TheEnumAlias::trait_'
|
||||
|
||||
//@ has foo/index.html '//a[@href="struct.TheStruct.html#method.inherent"]' 'TheStruct::inherent'
|
||||
// FIXME: this one should resolve to alias
|
||||
//@ has foo/index.html '//a[@href="struct.TheStruct.html#method.inherent"]' 'TheStructAlias::inherent'
|
||||
//@ has foo/index.html '//a[@href="enum.TheEnum.html#method.inherent"]' 'TheEnum::inherent'
|
||||
// FIXME: this one should resolve to alias
|
||||
//@ has foo/index.html '//a[@href="enum.TheEnum.html#method.inherent"]' 'TheEnumAlias::inherent'
|
||||
|
||||
pub struct TheStruct {
|
||||
pub the_field: i32,
|
||||
}
|
||||
|
||||
pub type TheStructAlias = TheStruct;
|
||||
|
||||
pub enum TheEnum {
|
||||
TheVariant { the_field: i32 },
|
||||
}
|
||||
|
||||
pub type TheEnumAlias = TheEnum;
|
||||
|
||||
pub trait Trait {
|
||||
fn trait_() {}
|
||||
}
|
||||
|
||||
impl Trait for TheStruct {}
|
||||
|
||||
impl Trait for TheEnumAlias {}
|
||||
|
||||
impl TheStruct {
|
||||
pub fn inherent() {}
|
||||
}
|
||||
|
||||
impl TheEnumAlias {
|
||||
pub fn inherent() {}
|
||||
}
|
||||
|
||||
pub union TheUnion {
|
||||
pub f1: usize,
|
||||
pub f2: isize,
|
||||
}
|
||||
|
||||
pub type TheUnionAlias = TheUnion;
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -13,7 +13,9 @@ pub fn foo() {}
|
|||
//@ has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#method.method"]' 'link from struct'
|
||||
//@ has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#method.clone"]' 'MyStruct::clone'
|
||||
//@ has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#associatedtype.Input"]' 'MyStruct::Input'
|
||||
pub struct MyStruct { foo: () }
|
||||
pub struct MyStruct {
|
||||
foo: (),
|
||||
}
|
||||
|
||||
impl Clone for MyStruct {
|
||||
fn clone(&self) -> Self {
|
||||
|
|
@ -31,8 +33,7 @@ impl T for MyStruct {
|
|||
|
||||
/// [link from method][MyStruct::method] on method
|
||||
//@ has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#method.method"]' 'link from method'
|
||||
fn method(i: usize) {
|
||||
}
|
||||
fn method(i: usize) {}
|
||||
}
|
||||
|
||||
/// Ambiguity between which trait to use
|
||||
|
|
@ -57,7 +58,7 @@ impl T2 for S {
|
|||
fn ambiguous_method() {}
|
||||
}
|
||||
|
||||
//@ has associated_items/enum.MyEnum.html '//a/@href' 'enum.MyEnum.html#variant.MyVariant'
|
||||
//@ has associated_items/enum.MyEnum.html '//a/@href' 'type.MyEnumAlias.html#variant.MyVariant'
|
||||
/// Link to [MyEnumAlias::MyVariant]
|
||||
pub enum MyEnum {
|
||||
MyVariant,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,12 @@ LL | const C: &'static str;
|
|||
...
|
||||
LL | fn take1(_: impl Trait1<C = "?">) {}
|
||||
| ^^^^^^^ ambiguous associated constant `C`
|
||||
|
|
||||
= help: consider introducing a new type parameter `T` and adding `where` constraints:
|
||||
where
|
||||
T: Trait1,
|
||||
T: Parent2::C = "?",
|
||||
T: Parent1::C = "?"
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
45
tests/ui/const-generics/incorrect-const-param.rs
Normal file
45
tests/ui/const-generics/incorrect-const-param.rs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
// #84327
|
||||
|
||||
struct VecWrapper<T>(Vec<T>);
|
||||
|
||||
// Correct
|
||||
impl<T, const N: usize> From<[T; N]> for VecWrapper<T>
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
fn from(slice: [T; N]) -> Self {
|
||||
VecWrapper(slice.to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
// Forgot const
|
||||
impl<T, N: usize> From<[T; N]> for VecWrapper<T> //~ ERROR expected value, found type parameter `N`
|
||||
where //~^ ERROR expected trait, found builtin type `usize`
|
||||
T: Clone,
|
||||
{
|
||||
fn from(slice: [T; N]) -> Self { //~ ERROR expected value, found type parameter `N`
|
||||
VecWrapper(slice.to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
// Forgot type
|
||||
impl<T, const N> From<[T; N]> for VecWrapper<T> //~ ERROR expected `:`, found `>`
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
fn from(slice: [T; N]) -> Self {
|
||||
VecWrapper(slice.to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
// Forgot const and type
|
||||
impl<T, N> From<[T; N]> for VecWrapper<T> //~ ERROR expected value, found type parameter `N`
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
fn from(slice: [T; N]) -> Self { //~ ERROR expected value, found type parameter `N`
|
||||
VecWrapper(slice.to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
70
tests/ui/const-generics/incorrect-const-param.stderr
Normal file
70
tests/ui/const-generics/incorrect-const-param.stderr
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
error: expected `:`, found `>`
|
||||
--> $DIR/incorrect-const-param.rs:26:16
|
||||
|
|
||||
LL | impl<T, const N> From<[T; N]> for VecWrapper<T>
|
||||
| ^ expected `:`
|
||||
|
|
||||
help: you likely meant to write the type of the const parameter here
|
||||
|
|
||||
LL | impl<T, const N: /* Type */> From<[T; N]> for VecWrapper<T>
|
||||
| ++++++++++++
|
||||
|
||||
error[E0423]: expected value, found type parameter `N`
|
||||
--> $DIR/incorrect-const-param.rs:16:28
|
||||
|
|
||||
LL | impl<T, N: usize> From<[T; N]> for VecWrapper<T>
|
||||
| - ^ not a value
|
||||
| |
|
||||
| found this type parameter
|
||||
|
||||
error[E0404]: expected trait, found builtin type `usize`
|
||||
--> $DIR/incorrect-const-param.rs:16:12
|
||||
|
|
||||
LL | impl<T, N: usize> From<[T; N]> for VecWrapper<T>
|
||||
| ^^^^^ not a trait
|
||||
|
|
||||
help: you might have meant to write a const parameter here
|
||||
|
|
||||
LL | impl<T, const N: usize> From<[T; N]> for VecWrapper<T>
|
||||
| +++++
|
||||
|
||||
error[E0423]: expected value, found type parameter `N`
|
||||
--> $DIR/incorrect-const-param.rs:20:24
|
||||
|
|
||||
LL | impl<T, N: usize> From<[T; N]> for VecWrapper<T>
|
||||
| - found this type parameter
|
||||
...
|
||||
LL | fn from(slice: [T; N]) -> Self {
|
||||
| ^ not a value
|
||||
|
||||
error[E0423]: expected value, found type parameter `N`
|
||||
--> $DIR/incorrect-const-param.rs:36:21
|
||||
|
|
||||
LL | impl<T, N> From<[T; N]> for VecWrapper<T>
|
||||
| - ^ not a value
|
||||
| |
|
||||
| found this type parameter
|
||||
|
|
||||
help: you might have meant to write a const parameter here
|
||||
|
|
||||
LL | impl<T, const N: /* Type */> From<[T; N]> for VecWrapper<T>
|
||||
| +++++ ++++++++++++
|
||||
|
||||
error[E0423]: expected value, found type parameter `N`
|
||||
--> $DIR/incorrect-const-param.rs:40:24
|
||||
|
|
||||
LL | impl<T, N> From<[T; N]> for VecWrapper<T>
|
||||
| - found this type parameter
|
||||
...
|
||||
LL | fn from(slice: [T; N]) -> Self {
|
||||
| ^ not a value
|
||||
|
|
||||
help: you might have meant to write a const parameter here
|
||||
|
|
||||
LL | impl<T, const N: /* Type */> From<[T; N]> for VecWrapper<T>
|
||||
| +++++ ++++++++++++
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0404, E0423.
|
||||
For more information about an error, try `rustc --explain E0404`.
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
#![feature(min_generic_const_args)]
|
||||
#![expect(incomplete_features)]
|
||||
|
||||
struct Y {
|
||||
stuff: [u8; { ([1, 2], 3, [4, 5]) }], //~ ERROR expected `usize`, found const tuple
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
error: expected `usize`, found const tuple
|
||||
--> $DIR/tuple_expr_arg_bad-issue-151048.rs:5:19
|
||||
|
|
||||
LL | stuff: [u8; { ([1, 2], 3, [4, 5]) }],
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -1,11 +1,6 @@
|
|||
#![feature(extern_item_impls)]
|
||||
// EIIs can, despite not being super useful, be declared in statement position
|
||||
// nested inside items. Items in statement position, when expanded as part of a macro,
|
||||
// need to be wrapped slightly differently (in an `ast::Statement`).
|
||||
// We did this on the happy path (no errors), but when there was an error, we'd
|
||||
// replace it with *just* an `ast::Item` not wrapped in an `ast::Statement`.
|
||||
// This caused an ICE (https://github.com/rust-lang/rust/issues/149980).
|
||||
// this test fails to build, but demonstrates that no ICE is produced.
|
||||
// EIIs cannot be used in statement position.
|
||||
// This is also a regression test for an ICE (https://github.com/rust-lang/rust/issues/149980).
|
||||
|
||||
fn main() {
|
||||
struct Bar;
|
||||
|
|
@ -13,4 +8,10 @@ fn main() {
|
|||
#[eii]
|
||||
//~^ ERROR `#[eii]` is only valid on functions
|
||||
impl Bar {}
|
||||
|
||||
|
||||
// Even on functions, eiis in statement position are rejected
|
||||
#[eii]
|
||||
//~^ ERROR `#[eii]` can only be used on functions inside a module
|
||||
fn foo() {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,17 @@
|
|||
error: `#[eii]` is only valid on functions
|
||||
--> $DIR/error_statement_position.rs:13:5
|
||||
--> $DIR/error_statement_position.rs:8:5
|
||||
|
|
||||
LL | #[eii]
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
error: `#[eii]` can only be used on functions inside a module
|
||||
--> $DIR/error_statement_position.rs:14:5
|
||||
|
|
||||
LL | #[eii]
|
||||
| ^^^^^^
|
||||
LL |
|
||||
LL | fn foo() {}
|
||||
| --- `#[eii]` is used on this item, which is part of another item's local scope
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
15
tests/ui/generics/wrong-number-of-args-in-macro.rs
Normal file
15
tests/ui/generics/wrong-number-of-args-in-macro.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// Regression test for #149559
|
||||
|
||||
struct Foo<T>; //~ ERROR type parameter `T` is never used
|
||||
|
||||
macro_rules! foo_ty {
|
||||
($a:ty, $b:ty) => {
|
||||
Foo<a, $b>
|
||||
//~^ ERROR cannot find type `a` in this scope
|
||||
//~| ERROR struct takes 1 generic argument but 2 generic arguments were supplied
|
||||
};
|
||||
}
|
||||
|
||||
fn foo<'a, 'b>() -> foo_ty!(&'b (), &'b ()) {}
|
||||
|
||||
fn main() {}
|
||||
44
tests/ui/generics/wrong-number-of-args-in-macro.stderr
Normal file
44
tests/ui/generics/wrong-number-of-args-in-macro.stderr
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
error[E0425]: cannot find type `a` in this scope
|
||||
--> $DIR/wrong-number-of-args-in-macro.rs:7:13
|
||||
|
|
||||
LL | Foo<a, $b>
|
||||
| ^ not found in this scope
|
||||
...
|
||||
LL | fn foo<'a, 'b>() -> foo_ty!(&'b (), &'b ()) {}
|
||||
| ----------------------- in this macro invocation
|
||||
|
|
||||
= note: this error originates in the macro `foo_ty` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: you might be missing a type parameter
|
||||
|
|
||||
LL | fn foo<'a, 'b, a>() -> foo_ty!(&'b (), &'b ()) {}
|
||||
| +++
|
||||
|
||||
error[E0107]: struct takes 1 generic argument but 2 generic arguments were supplied
|
||||
--> $DIR/wrong-number-of-args-in-macro.rs:7:9
|
||||
|
|
||||
LL | Foo<a, $b>
|
||||
| ^^^ expected 1 generic argument
|
||||
...
|
||||
LL | fn foo<'a, 'b>() -> foo_ty!(&'b (), &'b ()) {}
|
||||
| ----------------------- in this macro invocation
|
||||
|
|
||||
note: struct defined here, with 1 generic parameter: `T`
|
||||
--> $DIR/wrong-number-of-args-in-macro.rs:3:8
|
||||
|
|
||||
LL | struct Foo<T>;
|
||||
| ^^^ -
|
||||
= note: this error originates in the macro `foo_ty` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0392]: type parameter `T` is never used
|
||||
--> $DIR/wrong-number-of-args-in-macro.rs:3:12
|
||||
|
|
||||
LL | struct Foo<T>;
|
||||
| ^ unused type parameter
|
||||
|
|
||||
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
|
||||
= help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0107, E0392, E0425.
|
||||
For more information about an error, try `rustc --explain E0107`.
|
||||
|
|
@ -8,7 +8,7 @@ extern crate use_by_macro;
|
|||
use use_by_macro::*;
|
||||
|
||||
my_struct!(define);
|
||||
//~^ ERROR the name `MyStruct` is defined multiple times
|
||||
my_struct!(define);
|
||||
//~^ ERROR the name `MyStruct` is defined multiple times
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
error[E0428]: the name `MyStruct` is defined multiple times
|
||||
--> $DIR/cross-crate-redefine.rs:10:1
|
||||
--> $DIR/cross-crate-redefine.rs:11:1
|
||||
|
|
||||
LL | my_struct!(define);
|
||||
| ^^^^^^^^^^^^^^^^^^ `MyStruct` redefined here
|
||||
LL |
|
||||
LL | my_struct!(define);
|
||||
| ------------------ previous definition of the type `MyStruct` here
|
||||
LL | my_struct!(define);
|
||||
| ^^^^^^^^^^^^^^^^^^ `MyStruct` redefined here
|
||||
|
|
||||
= note: `MyStruct` must be defined only once in the type namespace of this module
|
||||
= note: this error originates in the macro `my_struct` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
|
|
|||
22
tests/ui/imports/overwrite-deep-glob.rs
Normal file
22
tests/ui/imports/overwrite-deep-glob.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
//@ check-pass
|
||||
|
||||
mod openssl {
|
||||
pub use self::handwritten::*;
|
||||
|
||||
mod handwritten {
|
||||
mod m1 {
|
||||
pub struct S {}
|
||||
}
|
||||
mod m2 {
|
||||
#[derive(Default)]
|
||||
pub struct S {}
|
||||
}
|
||||
|
||||
pub use self::m1::*; //~ WARN ambiguous glob re-exports
|
||||
pub use self::m2::*;
|
||||
}
|
||||
}
|
||||
|
||||
pub use openssl::*;
|
||||
|
||||
fn main() {}
|
||||
12
tests/ui/imports/overwrite-deep-glob.stderr
Normal file
12
tests/ui/imports/overwrite-deep-glob.stderr
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
warning: ambiguous glob re-exports
|
||||
--> $DIR/overwrite-deep-glob.rs:15:17
|
||||
|
|
||||
LL | pub use self::m1::*;
|
||||
| ^^^^^^^^^^^ the name `S` in the type namespace is first re-exported here
|
||||
LL | pub use self::m2::*;
|
||||
| ----------- but the name `S` in the type namespace is also re-exported here
|
||||
|
|
||||
= note: `#[warn(ambiguous_glob_reexports)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
||||
24
tests/ui/imports/overwrite-different-ambig-2.rs
Normal file
24
tests/ui/imports/overwrite-different-ambig-2.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
mod m1 {
|
||||
mod inner {
|
||||
pub struct S {}
|
||||
}
|
||||
pub use self::inner::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct S {}
|
||||
}
|
||||
|
||||
mod m2 {
|
||||
pub struct S {}
|
||||
}
|
||||
|
||||
// First we have a glob ambiguity in this glob (with `m2::*`).
|
||||
// Then we re-fetch `m1::*` because non-glob `m1::S` materializes from derive,
|
||||
// and we need to make sure that the glob ambiguity is not lost during re-fetching.
|
||||
use m1::*;
|
||||
use m2::*;
|
||||
|
||||
fn main() {
|
||||
let _: m1::S = S {}; //~ ERROR `S` is ambiguous
|
||||
//~| WARN this was previously accepted
|
||||
}
|
||||
49
tests/ui/imports/overwrite-different-ambig-2.stderr
Normal file
49
tests/ui/imports/overwrite-different-ambig-2.stderr
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
error: `S` is ambiguous
|
||||
--> $DIR/overwrite-different-ambig-2.rs:22:20
|
||||
|
|
||||
LL | let _: m1::S = S {};
|
||||
| ^ ambiguous name
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #114095 <https://github.com/rust-lang/rust/issues/114095>
|
||||
= note: ambiguous because of multiple glob imports of a name in the same module
|
||||
note: `S` could refer to the struct imported here
|
||||
--> $DIR/overwrite-different-ambig-2.rs:18:5
|
||||
|
|
||||
LL | use m1::*;
|
||||
| ^^^^^
|
||||
= help: consider adding an explicit import of `S` to disambiguate
|
||||
note: `S` could also refer to the struct imported here
|
||||
--> $DIR/overwrite-different-ambig-2.rs:19:5
|
||||
|
|
||||
LL | use m2::*;
|
||||
| ^^^^^
|
||||
= help: consider adding an explicit import of `S` to disambiguate
|
||||
= note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
Future incompatibility report: Future breakage diagnostic:
|
||||
error: `S` is ambiguous
|
||||
--> $DIR/overwrite-different-ambig-2.rs:22:20
|
||||
|
|
||||
LL | let _: m1::S = S {};
|
||||
| ^ ambiguous name
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #114095 <https://github.com/rust-lang/rust/issues/114095>
|
||||
= note: ambiguous because of multiple glob imports of a name in the same module
|
||||
note: `S` could refer to the struct imported here
|
||||
--> $DIR/overwrite-different-ambig-2.rs:18:5
|
||||
|
|
||||
LL | use m1::*;
|
||||
| ^^^^^
|
||||
= help: consider adding an explicit import of `S` to disambiguate
|
||||
note: `S` could also refer to the struct imported here
|
||||
--> $DIR/overwrite-different-ambig-2.rs:19:5
|
||||
|
|
||||
LL | use m2::*;
|
||||
| ^^^^^
|
||||
= help: consider adding an explicit import of `S` to disambiguate
|
||||
= note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
|
||||
|
||||
25
tests/ui/imports/overwrite-different-ambig.rs
Normal file
25
tests/ui/imports/overwrite-different-ambig.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
//@ check-pass
|
||||
//@ edition:2024
|
||||
|
||||
mod a {
|
||||
mod b {
|
||||
mod c {
|
||||
pub struct E;
|
||||
}
|
||||
mod d {
|
||||
mod c {
|
||||
pub struct E;
|
||||
}
|
||||
mod d {
|
||||
#[derive(Debug)]
|
||||
pub struct E;
|
||||
}
|
||||
pub use c::*;
|
||||
use d::*;
|
||||
}
|
||||
use c::*;
|
||||
use d::*;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
21
tests/ui/imports/overwrite-different-vis.rs
Normal file
21
tests/ui/imports/overwrite-different-vis.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
//@ check-pass
|
||||
|
||||
mod b {
|
||||
pub mod http {
|
||||
pub struct HeaderMap;
|
||||
}
|
||||
|
||||
pub(crate) use self::http::*;
|
||||
#[derive(Debug)]
|
||||
pub struct HeaderMap;
|
||||
}
|
||||
|
||||
mod a {
|
||||
pub use crate::b::*;
|
||||
|
||||
fn check_type() {
|
||||
let _: HeaderMap = crate::b::HeaderMap;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
28
tests/ui/imports/overwrite-different-warn-ambiguity.rs
Normal file
28
tests/ui/imports/overwrite-different-warn-ambiguity.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
//@ check-pass
|
||||
//@ edition:2024
|
||||
|
||||
mod framing {
|
||||
mod public_message_in {
|
||||
mod public_message {
|
||||
mod public_message {
|
||||
pub struct ConfirmedTranscriptHashInput;
|
||||
}
|
||||
mod public_message_in {
|
||||
use super::*;
|
||||
#[derive(Debug)]
|
||||
pub struct ConfirmedTranscriptHashInput;
|
||||
}
|
||||
pub use public_message::*;
|
||||
use public_message_in::*;
|
||||
}
|
||||
mod public_message_in {
|
||||
#[derive(Debug)]
|
||||
pub struct ConfirmedTranscriptHashInput;
|
||||
}
|
||||
pub use public_message::*;
|
||||
use public_message_in::*;
|
||||
}
|
||||
use public_message_in::*;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
//! More test coverage for <https://github.com/rust-lang/rust/issues/149692>; this test is
|
||||
//! specifically for `const` items.
|
||||
|
||||
macro_rules! m {
|
||||
(const $id:item()) => {}
|
||||
}
|
||||
|
||||
m!(const Self());
|
||||
//~^ ERROR expected one of `!` or `::`, found `(`
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
error: expected one of `!` or `::`, found `(`
|
||||
--> $DIR/kw-in-const-item-pos-recovery-149692.rs:8:14
|
||||
|
|
||||
LL | (const $id:item()) => {}
|
||||
| -------- while parsing argument for this `item` macro fragment
|
||||
...
|
||||
LL | m!(const Self());
|
||||
| ^ expected one of `!` or `::`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
19
tests/ui/parser/macro/kw-in-item-pos-recovery-149692.rs
Normal file
19
tests/ui/parser/macro/kw-in-item-pos-recovery-149692.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
//! Regression test for a diagnostic ICE where we tried to recover a keyword as the identifier when
|
||||
//! we are already trying to recover a missing keyword before item.
|
||||
//!
|
||||
//! See <https://github.com/rust-lang/rust/issues/149692>.
|
||||
|
||||
macro_rules! m {
|
||||
($id:item()) => {}
|
||||
}
|
||||
|
||||
m!(Self());
|
||||
//~^ ERROR expected one of `!` or `::`, found `(`
|
||||
|
||||
m!(Self{});
|
||||
//~^ ERROR expected one of `!` or `::`, found `{`
|
||||
|
||||
m!(crate());
|
||||
//~^ ERROR expected one of `!` or `::`, found `(`
|
||||
|
||||
fn main() {}
|
||||
29
tests/ui/parser/macro/kw-in-item-pos-recovery-149692.stderr
Normal file
29
tests/ui/parser/macro/kw-in-item-pos-recovery-149692.stderr
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
error: expected one of `!` or `::`, found `(`
|
||||
--> $DIR/kw-in-item-pos-recovery-149692.rs:10:8
|
||||
|
|
||||
LL | ($id:item()) => {}
|
||||
| -------- while parsing argument for this `item` macro fragment
|
||||
...
|
||||
LL | m!(Self());
|
||||
| ^ expected one of `!` or `::`
|
||||
|
||||
error: expected one of `!` or `::`, found `{`
|
||||
--> $DIR/kw-in-item-pos-recovery-149692.rs:13:8
|
||||
|
|
||||
LL | ($id:item()) => {}
|
||||
| -------- while parsing argument for this `item` macro fragment
|
||||
...
|
||||
LL | m!(Self{});
|
||||
| ^ expected one of `!` or `::`
|
||||
|
||||
error: expected one of `!` or `::`, found `(`
|
||||
--> $DIR/kw-in-item-pos-recovery-149692.rs:16:9
|
||||
|
|
||||
LL | ($id:item()) => {}
|
||||
| -------- while parsing argument for this `item` macro fragment
|
||||
...
|
||||
LL | m!(crate());
|
||||
| ^ expected one of `!` or `::`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue